home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / glimpse-2.1 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-16  |  87.8 KB  |  2,862 lines

  1. /* Copyright (c) 1994 Sun Wu, Udi Manber, Burra Gopal.  All Rights Reserved. */
  2. /* bgopal: (1993-4) redesigned/rewritten using agrep's library interface */
  3. #include <sys/param.h>
  4. #include <errno.h>
  5. #include "glimpse.h"
  6. #include "defs.h"
  7. #include <fcntl.h>
  8. #include "checkfile.h"
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/time.h>
  12.  
  13. #define CLIENTSERVER    1
  14. #define USE_MSGHDR    0
  15. #define USE_UNIXDOMAIN    0
  16. #define DEBUG    0
  17.  
  18. #define DEF_SERV_PORT    2001
  19. #define MIN_SERV_PORT    1024
  20. #define MAX_SERV_PORT    30000
  21. #define SERVER_QUEUE_SIZE    10    /* number of requests to buffer up while processing one request = 5 */
  22. #if    CLIENTSERVER
  23. #include <sys/socket.h>
  24. #include <sys/un.h>
  25. #include <netinet/in.h>
  26. #include <arpa/inet.h>
  27. #include <netdb.h>
  28. /* #include <sys/uio.h> */
  29. /* #include <sgtty.h> */
  30. #include <signal.h>
  31. #if defined(_IBMR2)
  32. #include <sys/select.h>
  33. #endif
  34. #endif    /*CLIENTSERVER*/
  35.  
  36. /* Borrowed from C-Lib */
  37. extern char **environ;
  38. extern int errno;
  39.  
  40. /* For client-server protocol */
  41. CHAR    SERV_HOST[MAXNAME];
  42. int    SERV_PORT;
  43. char    glimpse_reqbuf[MAX_ARGS*MAX_NAME_LEN];
  44. extern int glimpse_clientdied;    /* set if signal received about dead socket: need agrep variable so that exec() can return quickly */
  45.  
  46. /* Borrowed from agrep.c */
  47. extern int D_length;        /* global variable in agrep */
  48. extern int D;            /* global variable in agrep */
  49. extern int pattern_index;
  50. extern int REGEX, WORDBOUND;    /* To catch -w + REGEX error message in glimpse */
  51. /* These are used for byte level index search */
  52. extern CHAR CurrentFileName[MAX_LINE_LEN];
  53. extern int SetCurrentFileName;
  54. extern int CurrentByteOffset;
  55. extern int SetCurrentByteOffset;
  56. extern int execfd;
  57. extern int  agrep_initialfd;
  58. extern CHAR *agrep_inbuffer;
  59. extern int  agrep_inlen;
  60. extern int  agrep_inpointer;
  61. extern FILE *agrep_finalfp;
  62. extern CHAR *agrep_outbuffer;
  63. extern int  agrep_outlen;
  64. extern int  agrep_outpointer;
  65. extern int glimpse_call;    /* prevent agrep from printing out its usage */
  66. extern int glimpse_isserver;    /* prevent agrep from asking for user input */
  67. extern int use_previous_state;    /* speed up byte-level-search within one file */
  68. int    first_search = 1;    /* intra/interaction in process_query() and glimpse_search() */
  69.  
  70. /* Borrowed from build_in.c */
  71. extern int OneFilePerBlock;
  72. extern int StructuredIndex;
  73. extern unsigned int dest_index_set[REAL_PARTITION];
  74. extern unsigned char dest_index_buf[REAL_INDEX_BUF];
  75. extern unsigned int src_index_set[REAL_PARTITION];
  76. extern unsigned char src_index_buf[REAL_INDEX_BUF];
  77. extern int mask_int[32];
  78. extern int indexable_char[256];
  79. int test_indexable_char[256];
  80. extern int p_table[MAX_PARTITION];
  81. extern int GMAX_WORD_SIZE;
  82. extern int IndexNumber;        /* used in getword() */
  83. extern int InterpretSpecial;    /* used to "not-split" agrep-regexps */
  84. extern int UseFilters;        /* defined in build_in.c, used for filtering routines in io.c */
  85. extern int ByteLevelIndex;
  86.  
  87. /* OPTIONS/FLAGS */
  88. int    CONTACT_SERVER = 0;    /* Should client try to call server at all or just process query on its own? */
  89. int    NOBYTELEVEL = 0;    /* Some cases where we cannot do byte level fast-search: ALWAYS 0 if !ByteLevelIndex */
  90. int    OPTIMIZEBYTELEVEL = 0;    /* Some cases where we don't want to do byte level search since number of files is small */
  91. int    GLIMITOUTPUT = 0;    /* max no. of output lines: 0=>infinity=default=nolimit */
  92. int    GBESTMATCH = 0;        /* Should I change -B to -# where # = no. of errors? */
  93. int    GRECURSIVE = 0;
  94. int    GNOPROMPT = 0;
  95. int    GOUTTAIL = 0;
  96. int    GFILENAMEONLY = 0;    /* how to do it if it is an and expression in structured queries */
  97. int    GNOFILENAME=0;
  98. int    MATCHFILE = 0;
  99. int    PRINTATTR = 0;
  100. int    Pat_as_is=0;
  101. int    Only_first=0;
  102. int    WHOLEFILESCOPE=0;    /* used only when foundattr is NOT set: otherwise, scope is whole file anyway */
  103. int    foundattr=0;        /* set in split.c -- != 0 only when StructuredIndex AND query is structured */
  104.  
  105. /* structured queries */
  106. CHAR    ***attr_vals;        /* matrix of char pointers: row=max #of attributes, col=max possible values */
  107. CHAR    **attr_found;        /* did the expression corr. to each value in attr_vals match? */
  108. ParseTree *GParse;        /* what kind of expression corr. to attr are we looking for */
  109.  
  110. /* arbitrary booleans */
  111. ParseTree terminals[MAXNUM_PAT];    /* parse tree's terminal node pointers pt. to elements of this array; also used outside */ 
  112. char    matched_terminals[MAXNUM_PAT];    /* ...[i] is 1 if i'th terminal matched: used in filter_output and eval_tree */
  113. int    num_terminals;        /* number of terminal patterns */
  114. int    ComplexBoolean=0;    /* 1 if we need to use parse trees and the eval function */
  115.  
  116. /* index search */
  117. CHAR    *pat_list[MAXNUM_PAT];    /* complete words within global pattern */
  118. int    pat_lens[MAXNUM_PAT];    /* their lengths */
  119. int    pat_attr[MAXNUM_PAT];    /* set of attributes */
  120. int    is_mgrep_pat[MAXNUM_PAT];
  121. int    mgrep_pat_index[MAXNUM_PAT];
  122. int    num_mgrep_pat;
  123. CHAR    pat_buf[(MAXNUM_PAT + 2)*MAXPAT];
  124. int    pat_ptr = 0;
  125. extern char INDEX_DIR[MAX_LINE_LEN];
  126. char    TEMP_DIR[MAX_LINE_LEN];
  127. char    indexnumberbuf[256];    /* to read in first few lines of the index */
  128. char    *index_argv[MAX_ARGS];
  129. int    index_argc = 0;
  130. int    bestmatcherrors=0;    /* set during index search, used later on */
  131. int    patindex; 
  132. int    patbufpos = -1;
  133. char    tempfile[MAX_NAME_LEN];
  134.  
  135. /* agrep search */
  136. char    *agrep_argv[MAX_ARGS];
  137. int     agrep_argc = 0;
  138. CHAR    *FileOpt;        /* the option list after -F */
  139. int    fileopt_length;
  140. CHAR    GPattern[MAXPAT];
  141. int    GM;
  142. CHAR    APattern[MAXPAT];
  143. int    AM;
  144. CHAR    GD_pattern[MAXPAT];
  145. int    GD_length;
  146. CHAR    **GTextfiles;
  147. int    GFileIndex[MAXNUM_FILE];
  148. int    GNumfiles;
  149. int    GNumpartitions;
  150. CHAR    GProgname[MAXNAME];
  151.  
  152. /* persistent file descriptors */
  153. #if    BG_DEBUG
  154. FILE *debug;             /* file descriptor for debugging output */
  155. #endif    /*BG_DEBUG*/
  156. FILE    *indexfp = NULL;    /* glimpse index */
  157. FILE    *partfp = NULL;        /* glimpse partitions */
  158. FILE    *nullfp = NULL;        /* to discard output: agrep -s doesn't work properly */
  159. int    svstdin = 0, svstdout = 1, svstderr = 2;
  160.  
  161. /* Index manipulation */
  162. struct offsets **src_offset_table;
  163. struct offsets **multi_dest_offset_table[MAXNUM_PAT];
  164. unsigned int multi_dest_index_set[MAXNUM_PAT][REAL_PARTITION];
  165. extern free_list();
  166. struct stat index_stat_buf, file_stat_buf;
  167.  
  168. /* Direct agrep access for bytelevel-indices */
  169. extern int COUNT, INVERSE, TCOMPRESSED, NOFILENAME, POST_FILTER, OUTTAIL, BYTECOUNT,
  170.     LIMITOUTPUT, DELIMITER, SILENT, FILENAMEONLY, num_of_matched, prev_num_of_matched, FILEOUT;
  171. CHAR    matched_region[MAX_REGION_LIMIT*2 + MAXPATT*2];
  172. int    RegionLimit=DEFAULT_REGION_LIMIT;
  173.  
  174. /* Returns number of matched records/lines. Uses agrep's options to output stuff nicely */
  175. int
  176. glimpse_search(AM, APattern, GD_length, GD_pattern, filename, fileindex, src_offset_table, outfp)
  177.     int        AM;
  178.     unsigned char    APattern[];
  179.     int        GD_length;
  180.     unsigned char    GD_pattern[];
  181.     char        *filename;
  182.     int        fileindex;
  183.     struct offsets    *src_offset_table[];
  184.     FILE        *outfp;
  185. {
  186.     FILE        *infp;
  187.     char        sig[SIGNATURE_LEN];
  188.     struct offsets    **p1, *tp1;
  189.     CHAR        *text, *curtextend, *curtextbegin;
  190.     int        times;
  191.     int        num, ret, totalret = 0;
  192.     int        prevoffset, begininterval = 0, endinterval = -1;
  193.     CHAR        *beginpageptr, *endpageptr;
  194.     int        beginpage = 0, endpage = -1;
  195.     static int    MAXTIMES, MAXPGTIMES, pagesize;
  196.     static int    first_time = 1;
  197.  
  198.     /*
  199.      * If can't open file for read, quit
  200.      * For each offset for that file:
  201.      *    seek to that point
  202.      *    go back until delimiter, go forward until delimiter, output it: MAX_REGION_LIMIT is 16K on either side.
  203.      *    read in units of RegionLimit
  204.      *    before outputting matched record, use options to put prefixes (or use memagrep which does everything?)
  205.      */
  206.  
  207.     if (first_time) {
  208.         pagesize = DISKBLOCKSIZE;
  209.         MAXTIMES = ((MAX_REGION_LIMIT / RegionLimit) > 1) ? (MAX_REGION_LIMIT / RegionLimit) : 1;
  210.         MAXPGTIMES = ((MAX_REGION_LIMIT / pagesize) > 1) ? (MAX_REGION_LIMIT / pagesize) : 1;
  211.         first_time = 0;
  212.     }
  213.     /* Safety: must end/begin with delim */
  214.     memcpy(matched_region, GD_pattern, GD_length);
  215.     memcpy(matched_region+MAXPATT+2*MAX_REGION_LIMIT, GD_pattern, GD_length);
  216.     text = &matched_region[MAX_REGION_LIMIT+MAXPATT];
  217.  
  218.     if ((infp = fopen(filename, "r")) == NULL) return 0;
  219. #if    0
  220.     /* Cannot search in .CZ files since offset computations will be incorrect */
  221.     TCOMPRESSED = ON;
  222.     if (!tuncompressible_filename(file_list[i], strlen(file_list[i]))) TCOMPRESSED = OFF;
  223.     num_read = fread(sig, 1, SIGNATURE_LEN, infp);
  224.     if ((TCOMPRESSED == ON) && tuncompressible(sig, num_read)) {
  225.         EASYSEARCH = sig[SIGNATURE_LEN-1];
  226.         if (!EASYSEARCH) {
  227.             fprintf(stderr, "not compressed for easy-search: can miss some matches in: %s\n", CurrentFileName);    /* not filename!!! */
  228.         }
  229.     }
  230.     else TCOMPRESSED = OFF;
  231. #endif    /*0*/
  232.  
  233.     p1 = &src_offset_table[fileindex];
  234.     while (*p1 != NULL) {
  235.         if ( (begininterval <= (*p1)->offset) && (endinterval >= (*p1)->offset) ) {    /* already covered this area */
  236. #if    DEBUG
  237.             printf("ignoring %d in [%d,%d]\n", (*p1)->offset, begininterval, endinterval);
  238. #endif    /*DEBUG*/
  239.             tp1 = *p1;
  240.             *p1 = (*p1)->next;
  241.             my_free(tp1, sizeof(struct offsets));
  242.             continue;
  243.         }
  244.  
  245.         TCOMPRESSED = OFF;
  246. #if    0
  247.         if ( (beginpage <= (*p1)->offset) && (endpage >= (*p1)->offset) ) {    /* already read this area */
  248.             text += (*p1)->offset - prevoffset;
  249.             times = 0;
  250.             while (times < MAXPGTIMES) {
  251.                 if ( ((curtextend = forward_delimiter(text, endpageptr, GD_pattern, GD_length, 1)) < endpageptr) ||
  252.                      (endpageptr >= &matched_region[MAX_REGION_LIMIT*2+MAXPATT]) ) break;
  253.                 times ++;
  254.                 fseek(infp, endpage, 0);
  255.                 num = (&matched_region[MAX_REGION_LIMIT*2+MAXPATT] - endpageptr < pagesize) ? (&matched_region[MAX_REGION_LIMIT*2+MAXPATT*2] - endpageptr) : pagesize;
  256.                 if ((num = fread(endpageptr, 1, num, infp)) <= 0) break;
  257.                 endpage += num;
  258.                 endpageptr += num;
  259.                 if (endpageptr <= text) {
  260.                     curtextend = text;    /* error in value of offset: file was modified and offsets no longer true: your RISK! */
  261.                     break;
  262.                 }
  263.             }
  264.             times = 0;
  265.             while (times < MAXPGTIMES) {
  266.                 if ((curtextbegin = backward_delimiter(text, beginpageptr, GD_pattern, GD_length, 0)) > beginpageptr) break;
  267.                 if (beginpage > 0) {
  268.                     if (beginpageptr - pagesize < &matched_region[MAXPATT]) {
  269.                         if ((num = beginpageptr - &matched_region[MAXPATT]) <= 0) break;
  270.                     }
  271.                     else num = pagesize;
  272.                     beginpage -= num;
  273.                     beginpageptr -= num;
  274.                 }
  275.                 else break;
  276.                 times ++;
  277.                 fseek(infp, beginpage, 0);
  278.                 fread(beginpageptr, 1, num, infp);
  279.             }
  280.         }
  281.         else {
  282.             prevoffset = (*p1)->offset;
  283.             text = &matched_region[MAX_REGION_LIMIT+MAXPATT];
  284.             endpage = beginpage = ((*p1)->offset / pagesize) * pagesize;
  285.             /* endpage = (((*p1)->offset + pagesize) / pagesize) * pagesize */
  286.             endpageptr = beginpageptr = text - ((*p1)->offset - beginpage);
  287.             /* endpageptr = text + (endpage - (*p1)->offset); */
  288.             curtextbegin = curtextend = text;
  289.             times = 0;
  290.             while (times < MAXPGTIMES) {
  291.                 fseek(infp, endpage, 0);
  292.                 num = (&matched_region[MAX_REGION_LIMIT*2+MAXPATT] - endpageptr < pagesize) ? (&matched_region[MAX_REGION_LIMIT*2+MAXPATT*2] - endpageptr) : pagesize;
  293.                 if ((num = fread(endpageptr, 1, num, infp)) <= 0) break;
  294.                 endpage += num;
  295.                 endpageptr += num;
  296.                 if (endpageptr <= text) {
  297.                     curtextend = text;    /* error in value of offset: file was modified and offsets no longer true: your RISK! */
  298.                     break;
  299.                 }
  300.                 if (((curtextend = forward_delimiter(text, endpageptr, GD_pattern, GD_length, 1)) < endpageptr) ||
  301.                     (endpageptr >= &matched_region[MAX_REGION_LIMIT + 2*MAXPATT])) break;
  302.                 times ++;
  303.             }
  304.             times = 0;
  305.             while (times < MAXPGTIMES) {    /* I have already read the initial page since endpage is beginpage initially */
  306.                 if ((curtextbegin = backward_delimiter(text, beginpageptr, GD_pattern, GD_length, 0)) > beginpageptr) break;
  307.                 if (beginpage > 0) {
  308.                     if (beginpageptr - pagesize < &matched_region[MAXPATT]) {
  309.                         if ((num = beginpageptr - &matched_region[MAXPATT]) <= 0) break;
  310.                     }
  311.                     else num = pagesize;
  312.                     beginpage -= num;
  313.                     beginpageptr -= num;
  314.                 }
  315.                 else break;
  316.                 times ++;
  317.                 fseek(infp, beginpage, 0);
  318.                 fread(beginpageptr, 1, num, infp);
  319.             }
  320.         }
  321. #else    /*0*/
  322.         /* Find forward delimiter (including delimiter) */
  323.         times = 0;
  324.         fseek(infp, (*p1)->offset, 0);
  325.         while (times < MAXTIMES) {
  326.             if ((num = fread(text+RegionLimit*times, 1, RegionLimit, infp)) > 0)
  327.                 curtextend = forward_delimiter(text, text+RegionLimit*times+num, GD_pattern, GD_length, 1);
  328.             if ((curtextend < text+RegionLimit*times+num) || (num < RegionLimit)) break;
  329.             times ++;
  330.         }
  331.         /* Find backward delimiter (including delimiter) */
  332.         times = 0;
  333.         while (times < MAXTIMES) {
  334.             num = ((*p1)->offset - RegionLimit*(times+1)) > 0 ? ((*p1)->offset - RegionLimit*(times+1)) : 0;
  335.             fseek(infp, num, 0);
  336.             if (num > 0) {
  337.                 fread(text-RegionLimit*(times+1), 1, RegionLimit, infp);
  338.                 curtextbegin = backward_delimiter(text, text-RegionLimit*(times+1), GD_pattern, GD_length, 0);
  339.             }
  340.             else {
  341.                 fread(text-RegionLimit*times-(*p1)->offset, 1, (*p1)->offset, infp);
  342.                 curtextbegin = backward_delimiter(text, text-RegionLimit*times-(*p1)->offset, GD_pattern, GD_length, 0);
  343.             }
  344.             if ((num <= 0) || (curtextbegin > text-RegionLimit*(times+1))) break;
  345.             times ++;
  346.         }
  347. #endif    /*0*/
  348.  
  349.         /* set interval and delete the entry */
  350.         begininterval = (*p1)->offset - (text - curtextbegin);
  351.         endinterval = (*p1)->offset + (curtextend - text); 
  352. #if    DEBUG
  353.         *(curtextend + 1) = '\0';
  354.         printf("%s [%d < %d < %d] = %s\n", CurrentFileName, begininterval, (*p1)->offset, endinterval, curtextbegin);
  355. #endif    /*DEBUG*/
  356.         tp1 = *p1;
  357.         *p1 = (*p1)->next;
  358.         my_free(tp1, sizeof(struct offsets));
  359.         if (curtextend <= curtextbegin) continue;    /* error in offsets/delims */
  360.  
  361.         /*
  362.          * Don't call memagrep since that is heavy weight. Call exec
  363.          * directly after doing agrep_search()'s preprocessing here.
  364.          */
  365.         CurrentByteOffset = begininterval+1;
  366.         SetCurrentByteOffset = 1;
  367.         use_previous_state = 1;
  368.         first_search = 1;
  369.         if (first_search) {
  370.             if ((ret = memagrep_search(AM, APattern, curtextend-curtextbegin, curtextbegin, 0, outfp)) > 0)
  371.                 totalret ++; /* += ret */
  372.              else if ((ret < 0) && REGEX && (WORDBOUND || DELIMITER)) {
  373.                 fclose(infp);
  374.                 return -1;
  375.             }
  376.             first_search = 0;
  377.         }
  378.         else {    /* All agrep globals are properly set */
  379.             agrep_finalfp = (FILE *)outfp;
  380.             agrep_outlen = 0;
  381.             agrep_outbuffer = NULL;
  382.             agrep_outpointer = 0;
  383.             execfd = agrep_initialfd = -1;
  384.             agrep_inbuffer = curtextbegin;
  385.             agrep_inlen = curtextend - curtextbegin;
  386.             agrep_inpointer = 0;
  387.             if ((ret = exec(-1, NULL)) > 0)
  388.                 totalret ++; /* += ret; */
  389.              else if ((ret < 0) && REGEX && (WORDBOUND || DELIMITER)) {
  390.                 fclose(infp);
  391.                 return -1;
  392.             }
  393.         }
  394.  
  395.         if ((LIMITOUTPUT > 0) && (LIMITOUTPUT <= totalret)) break;    /* done */
  396.         if ((totalret > 0) && FILENAMEONLY) break;
  397.     }
  398.  
  399.     SetCurrentByteOffset = 0;
  400.     fclose(infp);
  401.     if (totalret > 0) {    /* dirty solution: must handle part of agrep here */
  402.         if (COUNT && !FILEOUT) {
  403.             if(!NOFILENAME) fprintf(outfp, "%s: %d\n", CurrentFileName, totalret);
  404.             else fprintf(outfp, "%d\n", totalret);
  405.         }
  406.         if (FILEOUT) file_out(CurrentFileName);
  407.     }
  408.     return totalret;
  409. }
  410.  
  411. #if    CLIENTSERVER
  412. int
  413. mystrlen(str, max)
  414.     char    *str;
  415.     int    max;
  416. {
  417.     int    i=0;
  418.  
  419.     while ((i<max) && (str[i] != '\0')) i++;
  420.     return i;
  421. }
  422.  
  423. readn(fd, ptr, nbytes)
  424. int    fd;
  425. char    *ptr;
  426. int    nbytes;
  427. {
  428.     int    nleft, nread;
  429.  
  430.     nleft = nbytes;
  431.     while (nleft > 0) {
  432.         nread = read(fd, ptr, nleft);
  433.         if (nread < 0) return(nread);
  434.         else if (nread == 0) break;    /* EOF */
  435.         nleft -= nread;
  436.         ptr += nread;
  437.     }
  438.     return (nbytes - nleft);
  439. }
  440.  
  441. writen(fd, ptr, nbytes)
  442. int    fd;
  443. char    *ptr;
  444. int    nbytes;
  445. {
  446.     int    nleft, nwritten;
  447.  
  448.     nleft = nbytes;
  449.     while (nleft > 0) {
  450.         nwritten = write(fd, ptr, nleft);
  451.         if (nwritten <= 0) return nwritten;
  452.         nleft -= nwritten;
  453.         ptr += nwritten;
  454.     }
  455.     return (nbytes - nleft);
  456. }
  457.  
  458. int
  459. readline(sockfd, ptr, maxlen)
  460. int    sockfd;
  461. char    *ptr;
  462. int    maxlen;
  463. {
  464.     int    n, rc;
  465.     char    c;
  466.  
  467.     for (n=1; n<maxlen; n++) {
  468.         if ((rc = readn(sockfd, &c, 1)) == 1) {
  469.             *ptr++ = c;
  470.             if (c == '\n') break;
  471.         } else if (rc == 0) {
  472.             if (n==1) return (0);    /* EOF */
  473.             else break;
  474.         } else return (-1);
  475.     }
  476.     *ptr = 0;
  477.     return n;
  478. }
  479.  
  480. #if    USE_MSGHDR
  481. /*
  482.  * This piece of code was causing compilation problems.
  483.  * It was not being used anyway. So it has been deleted.
  484.  * -bg, Jan 4th 95
  485.  */
  486.  
  487. int
  488. sendfile(sockfd, fds, num)
  489. int    sockfd, fds[], num;
  490. {
  491.     struct iovec    iov[1];
  492.     struct msghdr    msg;
  493.     int        ret;
  494.  
  495.     iov[0].iov_base = (char *) NULL;
  496.     iov[0].iov_len = 0;
  497.     msg.msg_iov = iov;
  498.     msg.msg_iovlen = 1;
  499.     msg.msg_name = (caddr_t) NULL;
  500.     msg.msg_namelen = 0;
  501.     msg.msg_accrights = (caddr_t) fds;
  502.     msg.msg_accrightslen = num * sizeof(int);
  503.  
  504.     errno = 0;
  505.     if ((ret = sendmsg(sockfd, &msg, 0)) < 0) {
  506. #if    DEBUG
  507.     printf("sendmsg ret = %x, errno = %d\n", ret, errno);
  508. #endif    /*DEBUG*/
  509.         return (-1);
  510.     }
  511. #if    DEBUG
  512.     printf("sent fds %x %x %x, ret = %x, errno = %d\n", fds[0], fds[1], fds[2], ret, errno);
  513. #endif    /*DEBUG*/
  514.     return (0);
  515. }
  516.  
  517. int
  518. send_clfds(sockfd, clstdin, clstdout, clstderr)
  519. int    sockfd, clstdin, clstdout, clstderr;
  520. {
  521.     int    fds[3];
  522.  
  523.     fds[0] = clstdin;
  524.     fds[1] = clstdout;
  525.     fds[2] = clstderr;
  526.     if (sendfile(sockfd, fds, 3) < 0) return -1;
  527.     return 0;
  528. }
  529.  
  530. int
  531. getfile(sockfd, fds, num)
  532. int    sockfd, fds[], num;
  533. {
  534.     struct iovec    iov[1];
  535.     struct msghdr    msg;
  536.     int        ret;
  537.  
  538.     iov[0].iov_base = (char *) NULL;
  539.     iov[0].iov_len = 0;
  540.     msg.msg_iov = iov;
  541.     msg.msg_iovlen = 1;
  542.     msg.msg_name = (caddr_t) NULL;
  543.     msg.msg_namelen = 0;
  544.     msg.msg_accrights = (caddr_t)fds;
  545.     msg.msg_accrightslen = num*sizeof(int);
  546.  
  547.     errno = 0;
  548.     if ((ret = recvmsg(sockfd, &msg, 0)) < 0) {
  549. #if    DEBUG
  550.         printf("bad recvmsg: ret = %x, errno = %d\n", ret, errno);
  551. #endif    /*DEBUG*/
  552.         return -1;
  553.     }
  554. #if    DEBUG
  555.     printf("got fds %x %x %x, ret = %x, errno = %d\n", fds[0], fds[1], fds[2], ret, errno);
  556. #endif    /*DEBUG*/
  557.     return 0;
  558. }
  559.  
  560. int
  561. get_clfds(sockfd, pclstdin, pclstdout, pclstderr)
  562. int    sockfd, *pclstdin, *pclstdout, *pclstderr;
  563. {
  564.     int    fds[3];
  565.  
  566.     if (getfile(sockfd, fds, 3) < 0) return -1;
  567.     if (((*pclstdin = fds[0]) < 0) || (*pclstdin >= 20)) return -1;
  568.     if (((*pclstdout = fds[1]) < 0) || (*pclstdout >= 20)) return -1;
  569.     if (((*pclstderr = fds[2]) < 0) || (*pclstderr >= 20)) return -1;
  570.     return 0;
  571. }
  572. #endif    /*USE_MSGHDR*/
  573.  
  574. int
  575. linearize(sockfd, reqbuf, reqlen, argc, argv, pid)
  576. int    sockfd;
  577. int    reqlen, argc;
  578. char    *reqbuf, *argv[];
  579. int    pid;
  580. {
  581.     int    i;
  582.     unsigned char    array[4];
  583.     int    ptr = 0;
  584.     int    len;
  585.  
  586.     array[0] = (pid & 0xff000000) >> 24;
  587.     array[1] = (pid & 0xff0000) >> 16;
  588.     array[2] = (pid & 0xff00) >> 8;
  589.     array[3] = (pid & 0xff);
  590.     if (sockfd >= 0) {
  591.         if (writen(sockfd, array, 4) < 4) return -1;
  592.     }
  593.     if (reqbuf != NULL) {
  594.         if (ptr + 4 >= reqlen) return -1;
  595.         memcpy(reqbuf+ptr, array, 4);
  596.         ptr += 4;
  597.     }
  598.  
  599.     array[0] = (argc & 0xff000000) >> 24;
  600.     array[1] = (argc & 0xff0000) >> 16;
  601.     array[2] = (argc & 0xff00) >> 8;
  602.     array[3] = (argc & 0xff);
  603.     if (sockfd >= 0) {
  604.         if (writen(sockfd, array, 4) < 4) return -1;
  605.     }
  606.     if (reqbuf != NULL) {
  607.         if (ptr + 4 >= reqlen) return -1;
  608.         memcpy(reqbuf+ptr, array, 4);
  609.         ptr += 4;
  610.     }
  611.  
  612.     for (i=0; i<argc; i++) {
  613.         len = strlen(argv[i]);
  614.         if (sockfd >= 0) {
  615.             if (writen(sockfd, argv[i], len + 1) < len + 1) return -1;
  616.             if (writen(sockfd, "\n", 1) < 1) return -1;    /* so that we can do gets */
  617.         }
  618.         if (reqbuf != NULL) {
  619.             if (ptr + len + 2 >= reqlen) return -1;
  620.             strcpy(reqbuf+ptr, argv[i]);
  621.             ptr += len+1;
  622.             reqbuf[ptr++] = '\0';    /* so that we can do strcpy */
  623.         }
  624. #if    DEBUG
  625.         printf("sending %s\n", argv[i]);
  626. #endif    /*DEBUG*/
  627.     }
  628.     return ptr;
  629. }
  630.  
  631. int
  632. delinearize(sockfd, reqbuf, reqlen, pargc, pargv, ppid)
  633. int    sockfd;
  634. int    reqlen, *pargc;
  635. char    *reqbuf, **pargv[];
  636. int    *ppid;
  637. {
  638.     int    i;
  639.     char    line[MAXLINE];
  640.     int    len;
  641.     int    ptr = 0;
  642.     unsigned char    array[4];
  643.  
  644.     *ppid = 0;
  645.     *pargc = 0;
  646.     *pargv = NULL;
  647.     memset(array, '\0', 4);
  648.  
  649.     if (sockfd >= 0) if (readn(sockfd, array, 4) != 4) return -1;
  650.     if (reqbuf != NULL) {
  651.         if (ptr+4 >= reqlen) return -1;
  652.         memcpy(array, reqbuf+ptr, 4);
  653.         ptr += 4;
  654.     }
  655.     *ppid = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
  656.  
  657.     memset(array, '\0', 4);
  658.     if (sockfd >= 0) if (readn(sockfd, array, 4) != 4) return -1;
  659.     if (reqbuf != NULL) {
  660.         if (ptr+4 >= reqlen) return -1;
  661.         memcpy(array, reqbuf+ptr, 4);
  662.         ptr += 4;
  663.     }
  664.     *pargc = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
  665. #if    DEBUG
  666.     printf("clargc=%x\n", *pargc);
  667. #endif    /*DEBUG*/
  668.     /* VERY important, set hard-coded limit to MAX_ARGS*MAX_NAME_LEN; otherwise can cause the server to allocate TONS of memory */
  669.     if (*pargc <= 0 || *pargc >= (MAX_ARGS*MAX_NAME_LEN)) { *pargc = 0; return -1; }
  670.  
  671.     if ((*pargv = (char **)my_malloc(sizeof(char *) * *pargc)) == NULL) {
  672.         /* no memory, so discard */
  673.         *pargc = 0;
  674.         return - 1;
  675.     }
  676.     memset(*pargv, '\0', sizeof(char *) * *pargc);
  677.     for (i=0; i<*pargc; i++) {
  678.         if (sockfd >= 0) {
  679.             if (readline(sockfd, line, MAXLINE) <= 0) return -1;
  680.             if ((len = mystrlen(line, MAXLINE)) <= 0) {
  681.                 i--;
  682.                 continue;
  683.             }
  684.             if (((*pargv)[i] = (char *)my_malloc(len + 2)) == NULL) return -1;
  685.             line[len] = '\0';    /* overwrite the '\n' */
  686.             strcpy((*pargv)[i], line);
  687.         }
  688.         if (reqbuf != NULL) {
  689.             if ( ((len = mystrlen(reqbuf+ptr, reqlen-ptr)) <= 0) || (len >= MAXLINE) ) return -1;
  690.             if (((*pargv)[i] = (char *)my_malloc(len + 2)) == NULL) return -1;
  691.             strcpy((*pargv)[i], reqbuf+ptr);
  692.             ptr += len + 2;
  693.         }
  694. #if    DEBUG
  695.         printf("clargv[%x]=%s\n", i, (*pargv)[i]);
  696. #endif    /*DEBUG*/
  697.     }
  698.     return ptr;
  699. }
  700.  
  701. int
  702. sendreq(sockfd, clstdin, clstdout, clstderr, clargc, clargv, clpid)
  703. int    sockfd, clstdin, clstdout, clstderr, clargc, clpid;
  704. char    *clargv[];
  705. {
  706. #if    USE_MSGHDR
  707.     struct iovec    iov[1];
  708.     struct msghdr    msg;
  709.     int        ret;
  710.     int        fds[3];
  711. #endif    /*USE_MSGHDR*/
  712.  
  713. #if    USE_MSGHDR
  714.     if ((ret = linearize(-1, glimpse_reqbuf, MAX_ARGS*MAX_NAME_LEN, clargc, clargv, clpid)) < 0) return -1;
  715.  
  716.     fds[2] = clstdin;
  717.     fds[1] = clstdout;
  718.     fds[0] = clstderr;
  719.  
  720.     iov[0].iov_base = (char *) glimpse_reqbuf;
  721.     iov[0].iov_len = ret;
  722.     msg.msg_iov = iov;
  723.     msg.msg_iovlen = 1;
  724.     msg.msg_name = (caddr_t) NULL;
  725.     msg.msg_namelen = 0;
  726.     msg.msg_accrights = (caddr_t) fds;
  727.     msg.msg_accrightslen = 2 * sizeof(int);    /* don't send clstdin */
  728.  
  729.     errno = 0;
  730.     if ((ret = sendmsg(sockfd, &msg, 0)) < 0) {
  731. #if    DEBUG
  732.     printf("sendmsg ret = %x, errno = %d\n", ret, errno);
  733. #endif    /*DEBUG*/
  734.         return (-1);
  735.     }
  736. #if    DEBUG
  737.     printf("sendreq %x %x %x, ret = %x, errno = %d\n", fds[0], fds[1], fds[2], ret, errno);
  738. #endif    /*DEBUG*/
  739. #else    /*USE_MSGHDR*/
  740.     if (linearize(sockfd, (char *)NULL, MAX_ARGS*MAX_NAME_LEN, clargc, clargv, clpid) < 0) return -1;
  741. #endif    /*USE_MSGHDR*/
  742.     return (0);
  743. }
  744.  
  745. int
  746. getreq(sockfd, pclstdin, pclstdout, pclstderr, pclargc, pclargv, pclpid)
  747. int    sockfd, *pclstdin, *pclstdout, *pclstderr, *pclargc, *pclpid;
  748. char    **pclargv[];
  749. {
  750. #if    USE_MSGHDR
  751.     struct iovec    iov[1];
  752.     struct msghdr    msg;
  753.     int        ret;
  754.     int        fds[3];
  755. #endif    /*USE_MSGHDR*/
  756.  
  757. #if    USE_MSGHDR
  758.     iov[0].iov_base = (char *) glimpse_reqbuf;
  759.     iov[0].iov_len = MAX_ARGS * MAX_NAME_LEN;
  760.     msg.msg_iov = iov;
  761.     msg.msg_iovlen = 1;
  762.     msg.msg_name = (caddr_t) NULL;
  763.     msg.msg_namelen = 0;
  764.     msg.msg_accrights = (caddr_t)fds;
  765.     msg.msg_accrightslen = 2*sizeof(int);
  766.  
  767.     errno = 0;
  768.     if ((ret = recvmsg(sockfd, &msg, 0)) < 0) {
  769. #if    DEBUG
  770.         printf("bad recvmsg: ret = %x, errno = %d\n", ret, errno);
  771. #endif    /*DEBUG*/
  772.         return -1;
  773.     }
  774.  
  775.     *pclstdin = fds[2];
  776.     *pclstdout = fds[1];
  777.     *pclstderr = fds[0];
  778.  
  779.     if ((ret == delinearize(-1, glimpse_reqbuf, MAX_ARGS * MAX_NAME_LEN, pclargc, pclargv, pclpid)) < 0) return -1;
  780. #if    DEBUG
  781.     printf("getreq %x %x %x, ret = %x, errno = %d\n", fds[0], fds[1], fds[2], ret, errno);
  782. #endif    /*DEBUG*/
  783. #else    /*USE_MSGHDR*/
  784.     if (delinearize(sockfd, (char *)NULL, MAX_ARGS * MAX_NAME_LEN, pclargc, pclargv, pclpid) < 0) return -1;
  785.     *pclstdin = -1;
  786.     *pclstdout = sockfd;
  787.     *pclstderr = sockfd;
  788. #endif    /*USE_MSGHDR*/
  789.     return (0);
  790. }
  791.  
  792. #endif    /*CLIENTSERVER*/
  793.  
  794. read_index(indexdir)
  795. char    indexdir[MAXNAME];
  796. {
  797.     char    *home;
  798.     char    s[MAXNAME];
  799.     int    ret;
  800.  
  801.     if (indexdir[0] == '\0') {
  802.         if ((home = (char *)getenv("HOME")) == NULL) {
  803.             getcwd(indexdir, MAXNAME-1);
  804.             fprintf(stderr, "using working-directory '%s' to locate index\n", indexdir);
  805.         }
  806.         else strncpy(indexdir, home, MAXNAME);
  807.     }
  808.     ret = chdir(indexdir);
  809.     if (getcwd(INDEX_DIR, MAXNAME-1) == NULL) strcpy(INDEX_DIR, indexdir);
  810.     if (ret < 0) {
  811.         fprintf(stderr, "using working-directory '%s' to locate index\n", INDEX_DIR);
  812.     }
  813.  
  814.     sprintf(s, "%s", INDEX_FILE);
  815.     indexfp = fopen(s, "r");
  816.     if(indexfp == NULL) {
  817.         fprintf(stderr, "can't open glimpse index-file %s/%s\n", INDEX_DIR, INDEX_FILE);
  818.         fprintf(stderr, "(use -H to give an index-directory or run 'glimpseindex' to make an index)\n");
  819.         return -1;
  820.     }
  821.     if (stat(s, &index_stat_buf) == -1) {
  822.         fprintf(stderr, "can't stat %s/%s\n", INDEX_DIR, s);
  823.         fclose(indexfp);
  824.         return -1;
  825.     }
  826.  
  827.     sprintf(s, "%s", P_TABLE);
  828.     partfp = fopen(s, "r");
  829.     if(partfp == NULL) {
  830.         fprintf(stderr, "can't open glimpse partition-table %s/%s\n", INDEX_DIR, P_TABLE);
  831.         fprintf(stderr, "(use -H to specify an index-directory or run glimpseindex to make an index)\n");
  832.         return -1;
  833.     }
  834.  
  835.     /* Get options */
  836. #if    BG_DEBUG
  837.     debug = fopen(DEBUG_FILE, "w+");
  838.     if(debug == NULL) {
  839.         fprintf(stderr, "can't open file %s/%s, errno=%d\n", INDEX_DIR, DEBUG_FILE, errno);
  840.         return(-1);
  841.     }
  842. #endif    /*BG_DEBUG*/
  843.     fgets(indexnumberbuf, 256, indexfp);
  844.     if(strstr(indexnumberbuf, "1234567890")) IndexNumber = ON;
  845.     else IndexNumber = OFF;
  846.     fscanf(indexfp, "%%%d\n", &OneFilePerBlock);
  847.     if (OneFilePerBlock < 0) {
  848.         ByteLevelIndex = ON;
  849.         OneFilePerBlock = -OneFilePerBlock;
  850.     }
  851.     fscanf(indexfp, "%%%d\n", &StructuredIndex);
  852.     /* Set WHOLEFILESCOPE for do-it-yourself request processing at client */
  853.     WHOLEFILESCOPE = 1;
  854.     if (StructuredIndex <= 0) {
  855.         WHOLEFILESCOPE = 0;
  856.         StructuredIndex = 0;
  857.         PRINTATTR = 0;    /* doesn't make sense: must not go into filter_output */
  858.     }
  859.     else if (-1 == (StructuredIndex = attr_load_names(ATTRIBUTE_FILE))) {
  860.         fprintf(stderr, "error in reading attribute file %s/%s\n", INDEX_DIR, ATTRIBUTE_FILE);
  861.         return(-1);
  862.     }
  863. #if    BG_DEBUG
  864.     fprintf(debug, "buf = %s OneFilePerBlock=%d StructuredIndex=%d\n", indexnumberbuf, OneFilePerBlock, StructuredIndex);
  865. #endif    /*BG_DEBUG*/
  866.     fclose(indexfp);
  867.     indexfp = NULL;
  868.  
  869.     /* Once IndexNumber info is available */
  870.     set_indexable_char(indexable_char);
  871.     set_indexable_char(test_indexable_char);
  872.     set_special_char(indexable_char);
  873.     return 0;
  874. }
  875.  
  876. /* MUST CARE IF PIPE/SOCKET IS BROKEN! ALSO SIGUSR1 (hardy@cs.colorado.edu) => QUIT CURRENT REQUEST. */
  877. int ignore_signal[32] = {    0,
  878.             0, 0, 1, 1, 1, 1, 1, 1,    /* all the tracing stuff: since default action is to dump core */
  879.             0, 0, 0, 0, 0, 0, 0, 0,
  880.             0, 0, 0, 0, 0, 0, 0, 0,
  881.             0, 0, 0, 0, 1, 0, 0 };    /* resource lost: since default action is to dump core */
  882.  
  883. /* S.t. sockets don't persist: they sometimes have a bad habit of doing so */
  884. void
  885. cleanup()
  886. {
  887.     int    i, q, k;
  888.  
  889.     /* ^C in the middle of a client call */
  890.     if (svstderr != 2) {
  891.         close(2);
  892.         dup(svstderr);
  893.     }
  894.     fprintf(stderr, "server cleaning up...\n");
  895.     for (i=0; i<64; i++) close(i);
  896.  
  897.     if (ByteLevelIndex) {
  898.         if (src_offset_table != NULL) for (k=0; k<OneFilePerBlock; k++) {
  899.             free_list(&src_offset_table[k]);
  900.         }
  901.         for (q=0; q<MAXNUM_PAT; q++) {
  902.             if (multi_dest_offset_table[q] != NULL) for (k=0; k<OneFilePerBlock; k++) {
  903.             free_list(&multi_dest_offset_table[q][k]);
  904.             }
  905.         }
  906.     }
  907.  
  908.     exit(3);
  909. }
  910.  
  911. #define QUITREQUESTMSG "glimpseserver: aborting request...\n"
  912. /* S.t. one request doesn't keep server occupied too long, when client already quits */
  913. void quitrequest(s)
  914. int s;
  915. {
  916.     /*
  917.      * Don't write onto stderr, since 2 is duped to sockfd => can cause recursive signal!
  918.      * Also, don't print error message more than once for quitting one request. The
  919.      * server receives signals for EVERY write it attempts when it finds a match: I could
  920.      * not find a way to prevent it, but agrep/bitap.c/fill_buf() was fixed to limit it.
  921.      * -- bg on 16th Feb 1995
  922.      */
  923.     if (!glimpse_clientdied && (s != SIGUSR1))    /* USR1 is a "friendly" cleanup message */
  924.         write(svstderr, QUITREQUESTMSG, strlen(QUITREQUESTMSG));
  925.  
  926.     glimpse_clientdied = 1;
  927. #ifdef __svr4__
  928.     /* Solaris 2.3 insists that you reset the signal handler */
  929.     (void)signal(s, quitrequest);
  930. #endif
  931. }
  932.  
  933. main(argc, argv)
  934. int argc;
  935. char *argv[];
  936. {
  937.     int    ret;
  938.     char    indexdir[MAXNAME];
  939.     char    **oldargv = argv;
  940.     int    oldargc = argc;
  941. #if    CLIENTSERVER
  942.     int    sockfd, newsockfd, clilen, len, clpid;
  943.     int    clout;
  944. #if    USE_UNIXDOMAIN
  945.     struct sockaddr_un cli_addr, serv_addr;
  946. #else    /*USE_UNIXDOMAIN*/
  947.     struct sockaddr_in cli_addr, serv_addr;
  948.     struct hostent *hp;
  949. #endif    /*USE_UNIXDOMAIN*/
  950.     int    cli_len;
  951.     int    clargc;
  952.     char    **clargv;
  953.     int    clstdin, clstdout, clstderr;
  954.     int    i;
  955.     char    array[4];
  956.     char    *p, c;
  957. #endif    /*CLIENTSERVER*/
  958.     int    quitwhile;
  959.  
  960. #if    CLIENTSERVER && ISSERVER
  961.     glimpse_isserver = 1;    /* I am the server */
  962. #else    /*CLIENTSERVER && ISSERVER*/
  963.     if (argc <= 1) return(usage());    /* Client nees at least 1 argument */
  964. #endif    /*CLIENTSERVER && ISSERVER*/
  965.  
  966. #define RETURNMAIN(val)\
  967. {\
  968.     if (indexfp != NULL) fclose(indexfp);\
  969.     if (partfp != NULL) fclose(partfp);\
  970.     if (nullfp != NULL) fclose(nullfp);\
  971.     indexfp = partfp = nullfp = NULL;\
  972.     if (StructuredIndex) {\
  973.         attr_free_table();\
  974.     }\
  975.     return (val);\
  976. }
  977.  
  978.     /* once-only initialization */
  979.     gethostname(SERV_HOST, MAXNAME - 2);
  980.     SERV_PORT = DEF_SERV_PORT;
  981.     srand(getpid());
  982.     umask(077);
  983.     strcpy(&GProgname[0], argv[0]);
  984.     region_initialize();
  985.     indexfp = partfp = nullfp = NULL;
  986.     if ((nullfp = fopen("/dev/null", "w")) == NULL) {
  987.         fprintf(stderr, "%s: cannot open for writing: /dev/null, errno=%d\n", argv[0], errno);
  988.         RETURNMAIN(-1);
  989.     }
  990.     InterpretSpecial = ON;
  991.     GMAX_WORD_SIZE = MAXPAT;
  992.     src_offset_table = NULL;
  993.     for (i=0; i<MAXNUM_PAT; i++) multi_dest_offset_table[i] = NULL;
  994.  
  995. #if    CLIENTSERVER
  996. #if    !ISSERVER
  997.     /* Check if client has too many arguments: then it is surely running as agrep since I have < half those options! */
  998.     if (argc > MAX_ARGS) goto doityourself;
  999. #endif    /*!ISSERVER*/
  1000.  
  1001.     while((--argc > 0) && (*++argv)[0] == '-' ) {
  1002.         p = argv[0] + 1;    /* ptr to first character after '-' */
  1003.         c = *(argv[0]+1);
  1004.         quitwhile = OFF;
  1005.         while (!quitwhile && (*p != '\0')) {
  1006.             c = *p;
  1007.             switch(c) {
  1008.             /* Look for -H option at server (only one that makes sense); if client has a -H, then it goes to doityourself */
  1009.             case 'H' :
  1010.                 if (*(p + 1) == '\0') {/* space after - option */
  1011.                     if (argc <= 1) {
  1012.                         fprintf(stderr, "%s: a directory name must follow the -H option\n", GProgname);
  1013.                         RETURNMAIN(usageS());
  1014.                     }
  1015.                     argv ++;
  1016.                     strcpy(indexdir, argv[0]);
  1017.                     argc --;
  1018.                 }
  1019.                 else {
  1020.                     strcpy(indexdir, p+1);
  1021.                 }
  1022.                 quitwhile = ON;
  1023.                 break;
  1024.  
  1025.             /* Recognized by both client and server */
  1026.             case 'J' :
  1027.                 if (*(p + 1) == '\0') {/* space after - option */
  1028.                     if (argc <= 1) {
  1029.                         fprintf(stderr, "%s: the server host name must follow the -J option\n", GProgname);
  1030. #if    ISSERVER
  1031.                         RETURNMAIN(usageS());
  1032. #else    /*ISSERVER*/
  1033.                         RETURNMAIN(usage());
  1034. #endif    /*ISSERVER*/
  1035.                     }
  1036.                     argv ++;
  1037.                     strcpy(SERV_HOST, argv[0]);
  1038.                     argc --;
  1039.                 }
  1040.                 else {
  1041.                     strcpy(SERV_HOST, p+1);
  1042.                 }
  1043.                 quitwhile = ON;
  1044.                 break;
  1045.  
  1046.             /* Recognized by both client and server */
  1047.             case 'K' :
  1048.                 if (*(p + 1) == '\0') {/* space after - option */
  1049.                     if (argc <= 1) {
  1050.                         fprintf(stderr, "%s: the server port must follow the -C option\n", GProgname);
  1051. #if    ISSERVER
  1052.                         RETURNMAIN(usageS());
  1053. #else    /*ISSERVER*/
  1054.                         RETURNMAIN(usage());
  1055. #endif    /*ISSERVER*/
  1056.                     }
  1057.                     argv ++;
  1058.                     SERV_PORT = atoi(argv[0]);
  1059.                     argc --;
  1060.                 }
  1061.                 else {
  1062.                     SERV_PORT = atoi(p+1);
  1063.                 }
  1064.                 if ((SERV_PORT < MIN_SERV_PORT) || (SERV_PORT > MAX_SERV_PORT)) {
  1065.                     fprintf(stderr, "Bad server port %d: must be in [%d, %d]: using default %d\n",
  1066.                         SERV_PORT, MIN_SERV_PORT, MAX_SERV_PORT, DEF_SERV_PORT);
  1067.                     SERV_PORT = DEF_SERV_PORT;
  1068.                 }
  1069.                 quitwhile = ON;
  1070.                 break;
  1071.  
  1072. #if    ISSERVER
  1073.             /* server cannot recognize any other option */
  1074.             default :
  1075.                 fprintf(stderr, "%s: server cannot recognize option: '%s'\n", GProgname, p);
  1076.                 RETURNMAIN(usageS());
  1077. #else    /*ISSERVER*/
  1078.  
  1079.             /* These have 1 argument each, so must do quitwhile */
  1080.             case 'd' :
  1081.             case 'e' :
  1082.             case 'k' :
  1083.             case 'D' :
  1084.             case 'F' : 
  1085.             case 'I' :
  1086.             case 'L' :
  1087.             case 'R' :
  1088.             case 'S' :
  1089.             case 'T' :
  1090.                 if (argv[0][2] == '\0') {/* space after - option */
  1091.                     if(argc <= 1) {
  1092.                         fprintf(stderr, "%s: the '-%c' option must have an argument\n", GProgname, c);
  1093.                         RETURNMAIN(usage());
  1094.                     }
  1095.                     argv++;
  1096.                     argc--;
  1097.                 }
  1098.                 quitwhile = ON;
  1099.                 break;
  1100.  
  1101.             /* These are illegal */
  1102.             case 'f' :
  1103.             case 'm' :
  1104.             case 'p' :
  1105.             case 'v' :
  1106.                 fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  1107.                 RETURNMAIN(usage());
  1108.                 break;
  1109.  
  1110.             /* They can't be patterns and filenames since they start with a -, these don't have arguments */
  1111.             case 'a' :
  1112.             case 'b' :
  1113.             case 'c' :
  1114.             case 'h' :
  1115.             case 'i' :
  1116.             case 'l' :
  1117.             case 'n' :
  1118.             case 'o' :
  1119.             case 'r' :
  1120.             case 's' :
  1121.             case 't' :
  1122.             case 'w' :
  1123.             case 'x' :
  1124.             case 'y' :
  1125.             case 'z' :
  1126.             case 'A' :
  1127.             case 'B' :
  1128.             case 'G' :
  1129.             case 'M' :
  1130.             case 'N' :
  1131.             case 'O' :
  1132.             case 'P' :
  1133.             case 'W' :
  1134.             case 'Z' :
  1135.                 break;
  1136.  
  1137.             case 'C':
  1138.                 CONTACT_SERVER = 1;
  1139.                 break;
  1140.  
  1141.             case 'V' :
  1142.                 printf("\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  1143.                 RETURNMAIN(0);
  1144.  
  1145.             default :
  1146.                 if (isdigit(c)) quitwhile = ON;
  1147.                 else {
  1148.                     fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  1149.                     RETURNMAIN(usage());
  1150.                 }
  1151.                 break;
  1152. #endif    /*ISSERVER*/
  1153.             } /* switch(c) */
  1154.             p ++;
  1155.         }
  1156.     }
  1157.  
  1158. #if    !ISSERVER
  1159.     /* Next arg must be the pattern: Check if the user wants to run the client as agrep, or doesn't want to contact the server */
  1160.     if ((argc > 1) || (!CONTACT_SERVER)) goto doityourself;
  1161. #endif    /*!ISSERVER*/
  1162.  
  1163.     argv = oldargv;
  1164.     argc = oldargc;
  1165. #endif    /*CLIENTSERVER*/
  1166.  
  1167. #if    ISSERVER && CLIENTSERVER
  1168.     if (-1 == read_index(indexdir)) RETURNMAIN(ret);
  1169.     for (i=0; i<32; i++)
  1170.         if (ignore_signal[i]) signal(i, SIG_IGN);
  1171.     signal(SIGHUP, cleanup);
  1172.     signal(SIGINT, cleanup);
  1173. #if defined(sco)
  1174.     if (((void (*)())-1 == signal(SIGPIPE, quitrequest)) ||
  1175.         ((void (*)())-1 == signal(SIGUSR1, quitrequest)))
  1176. #else
  1177.     if (((void (*)())-1 == signal(SIGPIPE, quitrequest)) ||
  1178.         ((void (*)())-1 == signal(SIGUSR1, quitrequest)) ||
  1179.         ((void (*)())-1 == signal(SIGURG, quitrequest))) 
  1180. #endif
  1181.         {
  1182.         /* Check for return values here since they ensure reliability */
  1183.         fprintf(stderr, "glimpseserver: Unable to install signal-handlers.\n");
  1184.         RETURNMAIN(-1);
  1185.     }
  1186.  
  1187. #if    USE_UNIXDOMAIN
  1188.     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  1189.         fprintf(stderr, "server cannot open socket for communication.\n");
  1190.         RETURNMAIN(-1);
  1191.     }
  1192.     unlink("/tmp/.glimpse_server");
  1193.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  1194.     serv_addr.sun_family = AF_UNIX;
  1195.     strcpy(serv_addr.sun_path, "/tmp/.glimpse_server");    /* < 108 ! */
  1196.     len = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  1197. #else    /*USE_UNIXDOMAIN*/
  1198.     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
  1199.         perror("glimpseserver: Cannot create socket");
  1200.         RETURNMAIN(-1);
  1201.     }
  1202.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  1203.         serv_addr.sin_family = AF_INET;
  1204.     serv_addr.sin_port = htons(SERV_PORT);
  1205. #if    0
  1206.     /* use host-names not internet style d.d.d.d notation */
  1207.     serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
  1208. #else
  1209.     /* 
  1210.      * We only want to accept connections from glimpse clients 
  1211.      * on the SERV_HOST, do not use INADDR_ANY!
  1212.      */
  1213.     if ((hp = gethostbyname(SERV_HOST)) == NULL) {
  1214.         perror("glimpseserver: Cannot resolve host");
  1215.         RETURNMAIN(-1);
  1216.     }
  1217.     memcpy((caddr_t)&serv_addr.sin_addr, hp->h_addr, hp->h_length);
  1218. #endif    /*0*/
  1219.     len = sizeof(serv_addr);
  1220. #endif    /*USE_UNIXDOMAIN*/
  1221.  
  1222.     if (bind(sockfd, (struct sockaddr *)&serv_addr, len) < 0) {
  1223.         perror("glimpseserver: Cannot bind to socket");
  1224.         RETURNMAIN(-1);
  1225.     }
  1226.     listen(sockfd, SERVER_QUEUE_SIZE);
  1227.  
  1228.     printf("glimpseserver: On-line (pid = %d, port = %d) waiting for request...\n", getpid(), SERV_PORT);
  1229.     fflush(stdout);    /* must fflush to print on server stdout */
  1230.     while (1) {
  1231.         /*
  1232.          *  Spin until sockfd is ready to do a non-blocking accept(2).
  1233.          *  We only wait for 15 seconds, because SunOS may
  1234.          *  swap us out if we block for 20 seconds or more.
  1235.          *  -- Courtesy: Darren Hardy, hardy@cs.colorado.edu
  1236.          */
  1237.         if (do_select(sockfd, 15) != 1)
  1238.             continue;
  1239.         /* get parameters */
  1240.         ret = 0;
  1241.         clargc = 0;
  1242.         clargv = NULL;
  1243.         cli_len = sizeof(cli_addr);
  1244.         if ((newsockfd = accept(sockfd, &cli_addr, &cli_len)) < 0) continue;
  1245.         if (getreq(newsockfd, &clstdin, &clstdout, &clstderr, &clargc, &clargv, &clpid) < 0) {
  1246.             ret = -1;
  1247. #if    DEBUG
  1248.             printf("getreq errno: %d\n", errno);
  1249. #endif    /*DEBUG*/
  1250.             goto end_process;
  1251.         }
  1252.  
  1253. #if    DEBUG
  1254.         printf("server processing request on %x\n", newsockfd);
  1255. #endif    /*DEBUG*/
  1256.         /*
  1257.          * Server doesn't wait for response, no point using
  1258.         svstdin = dup(0);
  1259.         close(0);
  1260.         dup(clstdin);
  1261.         close(clstdin);
  1262.          */
  1263.         /*
  1264.          * This is wrong since clstderr == clstdout!
  1265.         svstdout = dup(1);
  1266.         close(1);
  1267.         dup(clstdout);
  1268.         close(clstdout);
  1269.         svstderr = dup(2);
  1270.         close(2);
  1271.         dup(clstderr);
  1272.         close(clstderr);
  1273.         */
  1274.         svstdout = dup(1);
  1275.         svstderr = dup(2);
  1276.         close(1);
  1277.         close(2);
  1278.         dup(clstdout);
  1279.         dup(clstderr);
  1280.         close(clstdout);
  1281.         close(clstderr);
  1282.  
  1283.                         /*
  1284.              * IMPORTANT: Unbuffered I/O to the client!
  1285.                          * Done for Harvest since partial results might be
  1286.                          * needed and fflush will not flush partial results
  1287.                          * to the client if we type ^C and kill it: it puts
  1288.                          * them into /dev/null. This way, output is unbuffered
  1289.                          * and the client sees at least some results if killed.
  1290.                          */
  1291.                         setbuf(stdout, NULL);
  1292.                         setbuf(stderr, NULL);
  1293.  
  1294.             glimpse_call = 0;
  1295.             glimpse_clientdied = 0;
  1296.             ret = process_query(clargc, clargv);
  1297.         /*
  1298.          * Server doesn't wait for response, no point using
  1299.         close(0);
  1300.         dup(svstdin);
  1301.         close(svstdin);
  1302.         svstdin = 0;
  1303.          */
  1304.         if (glimpse_clientdied) {
  1305.             /*
  1306.              * This code is *ONLY* used as a safety net now.  
  1307.              * The old problem was that users would see portions 
  1308.              * of previous (and usually) unrelated queries!
  1309.              * glimpseserver now uses unbuffered I/O to the
  1310.              * client so all previous fwrite's to now are
  1311.              * gone.  But since this is such a nasty problem
  1312.              * we flush stdout to /dev/null just in case.
  1313.              */
  1314.             clout = open("/dev/null", O_WRONLY);
  1315.             close(1);
  1316.             dup(clout);
  1317.             close(clout);
  1318.             fflush(stdout);
  1319.         } 
  1320.  
  1321.         /* Restore svstdout and svstdout to stdout/stderr */
  1322.         close(1);
  1323.         dup(svstdout);
  1324.         close(svstdout);
  1325.         svstdout = 1;
  1326.         close(2);
  1327.         dup(svstderr);
  1328.         close(svstderr);
  1329.         svstderr = 2;
  1330.  
  1331.     end_process:
  1332. #if    USE_MSGHDR
  1333.         /* send reply and cleanup */
  1334.         array[0] = (ret & 0xff000000) >> 24;
  1335.         array[1] = (ret & 0xff0000) >> 16;
  1336.         array[2] = (ret & 0xff00) >> 8;
  1337.         array[3] = (ret & 0xff);
  1338.         writen(newsockfd, array, 4);
  1339. #endif    /*USE_MSGHDR*/
  1340. #if    DEBUG
  1341.         write(1, "done\n", 5);
  1342. #endif    /*DEBUG*/
  1343.         for (i=0; i<clargc; i++)
  1344.             if (clargv[i] != NULL) my_free(clargv[i], 0);
  1345.         if (clargv != NULL) my_free(clargv, 0);
  1346.         close(newsockfd);    /* if !USE_MSGHDR, client directly reads from socket and writes onto stdout until EOF */
  1347.     }
  1348. #else    /*ISSERVER && CLIENTSERVER*/
  1349.  
  1350. #if    CLIENTSERVER
  1351. #if    USE_UNIXDOMAIN
  1352.     if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
  1353.         perror("socket");
  1354.         goto doityourself;
  1355.     }
  1356.     memset((char *)&serv_addr, '\0', sizeof(serv_addr));
  1357.     serv_addr.sun_family = AF_UNIX;
  1358.     strcpy(serv_addr.sun_path, "/tmp/.glimpse_server");    /* < 108 ! */
  1359.     len = strlen(serv_addr.sun_path) + sizeof(serv_addr.sun_family);
  1360. #else    /*USE_UNIXDOMAIN*/
  1361.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
  1362.         perror("socket");
  1363.         goto doityourself;
  1364.     }
  1365.     serv_addr.sin_family = AF_INET;
  1366.     serv_addr.sin_port = htons(SERV_PORT);
  1367. #if    0
  1368.     /* use host-names not internet style d.d.d.d notation */
  1369.     serv_addr.sin__addr.s_addr = inet_addr(SERV_HOST);
  1370. #else    /*0*/
  1371.     if ((hp = gethostbyname(SERV_HOST)) == NULL) {
  1372.         fprintf(stderr, "gethostbyname (%s) failed\n", SERV_HOST);
  1373.         goto doityourself;
  1374.     }
  1375.     memcpy((caddr_t)&serv_addr.sin_addr, hp->h_addr, hp->h_length);
  1376. #endif    /*0*/
  1377.     len = sizeof(serv_addr);
  1378. #endif    /*USE_UNIXDOMAIN*/
  1379.  
  1380.     if (connect(sockfd, (struct sockaddr *)&serv_addr, len) < 0) {
  1381.                 char errbuf[4096];
  1382.                 sprintf(errbuf, "glimpse: Cannot contact glimpseserver: %s, port %d:", SERV_HOST, SERV_PORT);
  1383.                 perror(errbuf);
  1384.         /* perror(SERV_HOST); */
  1385. #if    DEBUG
  1386.         printf("connect errno: %d\n", errno);
  1387. #endif    /*DEBUG*/
  1388.         close(sockfd);
  1389.         goto doityourself;
  1390.     }
  1391.  
  1392.     if (sendreq(sockfd, fileno(stdin), fileno(stdout), fileno(stderr), argc, argv, getpid()) < 0) {
  1393.         perror("sendreq");
  1394. #if    DEBUG
  1395.         printf("sendreq errno: %d\n", errno);
  1396. #endif    /*DEBUG*/
  1397.         close(sockfd);
  1398.         goto doityourself;
  1399.     }
  1400.  
  1401. #if    USE_MSGHDR
  1402.     if (readn(sockfd, array, 4) != 4) {
  1403.         close(sockfd);
  1404.         goto doityourself;
  1405.     }
  1406.     ret = (array[0] << 24) + (array[1] << 16) + (array[2] << 8) + array[3];
  1407. #else    /*USE_MSGHDR*/
  1408. {
  1409.     /* 
  1410.      *  Dump everything the server writes into the socket onto 
  1411.      *  stdout until EOF/error.  Do this in a way so that *everything*
  1412.      *  the server sends is dumped to stdout by the client.  The
  1413.      *  client might die suddenly via ^C or SIGTERM, but we still
  1414.      *  want the results.
  1415.      */
  1416.     char tmpbuf[1024];
  1417.     int n;
  1418.  
  1419.     while ((n = read(sockfd, tmpbuf, 1024)) > 0) {
  1420.         write(fileno(stdout), tmpbuf, n);
  1421.     }
  1422. }
  1423. #endif    /*USE_MSGHDR*/
  1424.  
  1425.     close(sockfd);
  1426.     RETURNMAIN(ret);
  1427.  
  1428. doityourself:
  1429. #if    DEBUG
  1430.     printf("doing it myself :-(\n");
  1431. #endif    /*DEBUG*/
  1432. #endif    /*CLIENTSERVER*/
  1433.     setbuf(stdout, NULL);    /* Unbuffered I/O to always get every result */
  1434.     setbuf(stderr, NULL);
  1435.     glimpse_call = 0;
  1436.     glimpse_clientdied = 0;
  1437.     ret = process_query(oldargc, oldargv);
  1438.     RETURNMAIN(ret);
  1439. #endif    /*ISSERVER && CLIENTSERVER*/
  1440. }
  1441.  
  1442. process_query(argc, argv)
  1443. int argc; 
  1444. char *argv[];
  1445. {
  1446.     int    searchpercent;
  1447.     int    num_blocks;
  1448.     int    i, j;
  1449.     int    iii; /* Udi */
  1450.     int    jjj;
  1451.     char    c;
  1452.     char    *p;
  1453.     int    ret;
  1454.     int    jj;
  1455.     int    quitwhile;
  1456.     char    indexdir[MAX_LINE_LEN];
  1457.     int    oldargc = argc;
  1458.     char    **oldargv = argv;
  1459.     CHAR    dummypat[MAX_PAT];
  1460.     int    dummylen=0;
  1461.     int    my_M_index, my_P_index, my_b_index, my_A_index, my_l_index = -1, my_B_index = -1;
  1462.     char    **outname;
  1463.     int    gnum_of_matched = 0;
  1464.     int    foundpat = 0;
  1465.     int    wholefilescope=0;
  1466.  
  1467. /*
  1468.  * Macro to destroy EVERYTHING before return since we might want to make this a
  1469.  * library function later on: convention is that after destroy, objects are made
  1470.  * NULL throughout the source code, and are all set to NULL at initialization time.
  1471.  * DO agrep_argv, index_argv and FileOpt my_malloc/my_free optimizations later.
  1472.  * my_free calls have 2nd parameter = 0 if the size is not easily determinable.
  1473.  */
  1474. #define RETURN(val) \
  1475. {\
  1476.     int    q,k;\
  1477. \
  1478.     first_search = 0;\
  1479.     for (k=0; k<MAX_ARGS; k++) {\
  1480.         if (agrep_argv[k] != NULL) my_free(agrep_argv[k], 0);\
  1481.         if (index_argv[k] != NULL) my_free(index_argv[k], 0);\
  1482.         agrep_argv[k] = index_argv[k] = NULL;\
  1483.     }\
  1484.     if (FileOpt != NULL) my_free(FileOpt, MAXFILEOPT);\
  1485.     FileOpt = NULL;\
  1486.     for (k=0; k<MAXNUM_PAT; k++) {\
  1487.         if (pat_list[k] != NULL) my_free(pat_list[k], 0);\
  1488.         pat_list[k] = NULL;\
  1489.     }\
  1490.     sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());\
  1491.     unlink(tempfile);\
  1492.     sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());\
  1493.     unlink(outname[0]);\
  1494.     my_free(outname[0], 0);\
  1495.     my_free(outname, 0);\
  1496. \
  1497.     if (ByteLevelIndex) {\
  1498.         if (src_offset_table != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  1499.             free_list(&src_offset_table[k]);\
  1500.         }\
  1501.         /* Don't make src_offset_table itself NULL: it will be bzero-d below if !NULL */\
  1502.         for (q=0; q<MAXNUM_PAT; q++) {\
  1503.             if (multi_dest_offset_table[q] != NULL) for (k=0; k<OneFilePerBlock; k++) {\
  1504.             free_list(&multi_dest_offset_table[q][k]);\
  1505.             }\
  1506.             /* Don't make multi_dest_offset_table[q] itself NULL: it will be bzero-d below if !NULL */\
  1507.         }\
  1508.     }\
  1509.     for (k=0; k<num_terminals;k++)\
  1510.         free(terminals[k].data.leaf.value);\
  1511.     if (ComplexBoolean) destroy_tree(&GParse);\
  1512.     for (k=0; k<GNumfiles; k++) {\
  1513.         my_free(GTextfiles[k], 0);\
  1514.         GTextfiles[k] = NULL;\
  1515.     }\
  1516.     /* Don't free the GTextfiles buffer itself since it is allocated once in get_filename.c */\
  1517.     return (val);\
  1518. }
  1519.  
  1520.     /*
  1521.      * Initialize
  1522.      */
  1523.     strcpy(&GProgname[0], argv[0]);
  1524.     if (argc <= 1) return(usage());
  1525.     strcpy(TEMP_DIR, "/tmp");
  1526.     D_length = 0;
  1527.     D = 0;
  1528.     pattern_index = 0;
  1529.     first_search = 1;
  1530.     outname  = (char **)my_malloc(sizeof(char *));
  1531.     outname[0] = (char *)my_malloc(MAX_LINE_LEN);
  1532.     NOBYTELEVEL = 0;
  1533.     OPTIMIZEBYTELEVEL = 0;
  1534.     GLIMITOUTPUT = 0;
  1535.     GBESTMATCH = 0;
  1536.     GRECURSIVE = 0;
  1537.     GNOPROMPT = 0;
  1538.     GOUTTAIL = 2;    /* stupid fix, but works */
  1539.     GFILENAMEONLY = 0;
  1540.     GNOFILENAME = 0;
  1541.     MATCHFILE = 0;
  1542.     PRINTATTR = 0;
  1543.     Pat_as_is=0;
  1544.     Only_first = 0;
  1545.     foundattr = 0;
  1546.     ComplexBoolean = 0;
  1547.     bestmatcherrors = 0;
  1548.     patbufpos = -1;
  1549.     RegionLimit=DEFAULT_REGION_LIMIT;
  1550.     strcpy(GD_pattern, "\n");
  1551.     GD_length = strlen(GD_pattern);
  1552.     indexdir[0] = '\0';
  1553.     memset(index_argv, '\0', sizeof(char *) * MAX_ARGS);
  1554.     index_argc = 0;
  1555.     memset(agrep_argv, '\0', sizeof(char *) * MAX_ARGS);
  1556.     agrep_argc = 0;
  1557.     FileOpt = NULL;
  1558.     fileopt_length = 0;
  1559.     memset(pat_list, '\0', sizeof(char *) * MAXNUM_PAT);
  1560.     memset(pat_attr, '\0', sizeof(int) * MAXNUM_PAT);
  1561.     for (i=0; i<MAX_ARGS; i++)
  1562.         index_argv[i] = (char *)my_malloc(MaxNameLength + 2);
  1563.     memset(is_mgrep_pat, '\0', sizeof(int) * MAXNUM_PAT);
  1564.     memset(mgrep_pat_index, '\0', sizeof(int) *MAXNUM_PAT);
  1565.     num_mgrep_pat = 0;
  1566.     memset(pat_buf, '\0', (MAXNUM_PAT + 2)*MAXPAT);
  1567.     pat_ptr = 0;
  1568.     sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());
  1569.     /* Set WHOLEFILESCOPE for per-request processing at server */
  1570.     if (StructuredIndex) WHOLEFILESCOPE = 1;
  1571.     else WHOLEFILESCOPE = 0;
  1572.  
  1573.     if (argc > MAX_ARGS) {
  1574. #if    ISSERVER
  1575.     fprintf(stderr, "too many arguments %d obtained on server!\n", argc);
  1576. #endif    /*ISSERVER*/
  1577.         i = fileagrep(oldargc, oldargv, 0, stdout);
  1578.         RETURN(i);
  1579.     }
  1580.  
  1581.     /*
  1582.      * Process what options you can, then call fileagrep_init() to set
  1583.      * options in agrep and get the pattern. Then, call fileagrep_search().
  1584.      * Begin by copying options into agrep_argv assuming glimpse was not
  1585.      * called as agrep (optimistic :-).
  1586.      */
  1587.  
  1588.     agrep_argc = 0;
  1589.     for (i=0; i<MAX_ARGS; i++) agrep_argv[i] = NULL;
  1590.     agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1591.     strcpy(agrep_argv[agrep_argc], argv[0]);    /* copy the name of the program anyway */
  1592.     agrep_argc ++;
  1593.  
  1594.     /* In glimpse, you should never output filenames with zero matches */
  1595.     if (agrep_argc + 1 >= MAX_ARGS) {
  1596.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1597.         RETURN(usage());
  1598.     }
  1599.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1600.     agrep_argv[agrep_argc][0] = '-';
  1601.     agrep_argv[agrep_argc][1] = 'z';
  1602.     agrep_argv[agrep_argc][2] = '\0';
  1603.     agrep_argc ++;
  1604.  
  1605.     /* In glimpse, you should always print pattern when using mgrep (user can't do -f or -m)! */
  1606.     if (agrep_argc + 1 >= MAX_ARGS) {
  1607.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1608.         RETURN(usage());
  1609.     }
  1610.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1611.     agrep_argv[agrep_argc][0] = '-';
  1612.     agrep_argv[agrep_argc][1] = 'P';
  1613.     agrep_argv[agrep_argc][2] = '\0';
  1614.     my_P_index = agrep_argc;
  1615.     agrep_argc ++;
  1616.  
  1617.     /* In glimpse, you should always output multiple when doing mgrep */
  1618.     if (agrep_argc + 1 >= MAX_ARGS) {
  1619.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1620.         RETURN(usage());
  1621.     }
  1622.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1623.     agrep_argv[agrep_argc][0] = '-';
  1624.     agrep_argv[agrep_argc][1] = 'M';
  1625.     agrep_argv[agrep_argc][2] = '\0';
  1626.     my_M_index = agrep_argc;
  1627.     agrep_argc ++;
  1628.  
  1629.     /* In glimpse, you should print the byte offset if there is a structured query */
  1630.     if (agrep_argc + 1 >= MAX_ARGS) {
  1631.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1632.         RETURN(usage());
  1633.     }
  1634.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1635.     agrep_argv[agrep_argc][0] = '-';
  1636.     agrep_argv[agrep_argc][1] = 'b';
  1637.     agrep_argv[agrep_argc][2] = '\0';
  1638.     my_b_index = agrep_argc;
  1639.     agrep_argc ++;
  1640.  
  1641.     /* In glimpse, you should always have space for doing -m if required */
  1642.     if (agrep_argc + 2 >= MAX_ARGS) {
  1643.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1644.         RETURN(usage());
  1645.     }
  1646.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1647.     agrep_argv[agrep_argc][0] = '-';
  1648.     agrep_argv[agrep_argc][1] = 'm';
  1649.     agrep_argv[agrep_argc][2] = '\0';
  1650.     agrep_argc ++;
  1651.     agrep_argv[agrep_argc] = (char *)my_malloc(2);    /* no op */
  1652.     agrep_argv[agrep_argc][0] = '\0';
  1653.     agrep_argc ++;
  1654.  
  1655.     /* Add -A option to print filenames as default */
  1656.     if (agrep_argc + 1 >= MAX_ARGS) {
  1657.         fprintf(stderr, "%s: too many options!\n", GProgname);
  1658.         RETURN(usage());
  1659.     }
  1660.     agrep_argv[agrep_argc] = (char *)my_malloc(sizeof(char *));
  1661.     agrep_argv[agrep_argc][0] = '-';
  1662.     agrep_argv[agrep_argc][1] = 'A';
  1663.     agrep_argv[agrep_argc][2] = '\0';
  1664.     my_A_index = agrep_argc;
  1665.     agrep_argc ++;
  1666.  
  1667.     while((agrep_argc < MAX_ARGS) && (--argc > 0) && (*++argv)[0] == '-' ) {
  1668.         p = argv[0] + 1;    /* ptr to first character after '-' */
  1669.         c = *(argv[0]+1);
  1670.         quitwhile = OFF;
  1671.         while (!quitwhile && (*p != '\0')) {
  1672.             c = *p;
  1673.             switch(c) {
  1674.             case 'F' : 
  1675.                 MATCHFILE = ON;
  1676.                 FileOpt = (CHAR *)my_malloc(MAXFILEOPT);
  1677.                 if (*(p + 1) == '\0') {/* space after - option */
  1678.                     if(argc <= 1) {
  1679.                         fprintf(stderr, "%s: a file pattern must follow the -F option\n", GProgname);
  1680.                         RETURN(usage());
  1681.                     }
  1682.                     argv++;
  1683.                     if ((dummylen = strlen(argv[0])) > MAXFILEOPT) {
  1684.                         fprintf(stderr, "%s: -F option list too long\n", GProgname);
  1685.                         RETURN(usage());
  1686.                     }
  1687.                     strcpy(FileOpt, argv[0]);
  1688.                     argc--;
  1689.                 } else {
  1690.                     if ((dummylen = strlen(p+1)) > MAXFILEOPT) {
  1691.                         fprintf(stderr, "%s: -F option list too long\n", GProgname);
  1692.                         RETURN(usage());
  1693.                     }
  1694.                     strcpy(FileOpt, p+1);
  1695.                 } /* else */
  1696.                 quitwhile = ON;
  1697.                 break;
  1698.  
  1699.             /*
  1700.              * indexed search - use the exact pattern to search the index as well:
  1701.              * not implemented yet
  1702.             case 'X' :
  1703.                 Pat_as_is = ON;
  1704.                 break;
  1705.              */
  1706.  
  1707.             /* search the index only and output the number of blocks */
  1708.             case 'N' :
  1709.                 Only_first = ON;
  1710.                 break ;
  1711.  
  1712.             /* go to home directory to find the index: even if server overwrites indexdir here, it won't overwrite INDEX_DIR until read_index() */
  1713.             case 'H' :
  1714.                 if (*(p + 1) == '\0') {/* space after - option */
  1715.                     if (argc <= 1) {
  1716.                         fprintf(stderr, "%s: a directory name must follow the -H option\n", GProgname);
  1717.                         RETURN(usage());
  1718.                     }
  1719.                     argv ++;
  1720. #if    !ISSERVER
  1721.                     strcpy(indexdir, argv[0]);
  1722. #endif    /*!ISSERVER*/
  1723.                     argc --;
  1724.                 }
  1725. #if    !ISSERVER
  1726.                 else {
  1727.                     strcpy(indexdir, p+1);
  1728.                 }
  1729.                 agrep_argv[agrep_argc] = (char *)my_malloc(4);
  1730.                 strcpy(agrep_argv[agrep_argc], "-H");
  1731.                 agrep_argc ++;
  1732.                 agrep_argv[agrep_argc] = (char *)my_malloc(strlen(indexdir) + 2);
  1733.                 strcpy(agrep_argv[agrep_argc], indexdir);
  1734.                 agrep_argc ++;
  1735. #endif    /*!ISSERVER*/
  1736.                 quitwhile = ON;
  1737.                 break;
  1738.  
  1739.             /* go to temp directory to create temp files */
  1740.             case 'T' :
  1741.                 if (*(p + 1) == '\0') {/* space after - option */
  1742.                     if (argc <= 1) {
  1743.                         fprintf(stderr, "%s: a directory name must follow the -T option\n", GProgname);
  1744.                         RETURN(usage());
  1745.                     }
  1746.                     argv ++;
  1747.                     strcpy(TEMP_DIR, argv[0]);
  1748.                     argc --;
  1749.                 }
  1750.                 else {
  1751.                     strcpy(TEMP_DIR, p+1);
  1752.                 }
  1753.                 sprintf(tempfile, "%s/.glimpse_tmp.%d", TEMP_DIR, getpid());
  1754.                 quitwhile = ON;
  1755.                 break;
  1756.  
  1757.             case 'R' :
  1758.                 if (*(p + 1) == '\0') {/* space after - option */
  1759.                     if (argc <= 1) {
  1760.                         fprintf(stderr, "%s: the record size must follow the -R option\n", GProgname);
  1761.                         RETURN(usage());
  1762.                     }
  1763.                     argv ++;
  1764.                     RegionLimit = atoi(argv[0]);
  1765.                     argc --;
  1766.                 }
  1767.                 else {
  1768.                     RegionLimit = atoi(p+1);
  1769.                 }
  1770.                 if ((RegionLimit <= 0) || (RegionLimit > MAX_REGION_LIMIT)) {
  1771.                     fprintf(stderr, "Bad record size %d: must be in [%d, %d]: using default %d\n",
  1772.                         RegionLimit, 1, MAX_REGION_LIMIT, DEFAULT_REGION_LIMIT);
  1773.                     RegionLimit = DEFAULT_REGION_LIMIT;
  1774.                 }
  1775.                 quitwhile = ON;
  1776.                 break;
  1777.  
  1778.             /* doesn't matter if we overwrite the value in the client since the same value would have been picked up in main() anyway */
  1779.             case 'J' :
  1780.                 if (*(p + 1) == '\0') {/* space after - option */
  1781.                     if (argc <= 1) {
  1782.                         fprintf(stderr, "%s: the server host name must follow the -J option\n", GProgname);
  1783.                         RETURNMAIN(usageS());
  1784.                     }
  1785.                     argv ++;
  1786. #if    !ISSERVER
  1787.                     strcpy(SERV_HOST, argv[0]);
  1788. #endif    /*!ISSERVER*/
  1789.                     argc --;
  1790.                 }
  1791. #if    !ISSERVER
  1792.                 else {
  1793.                     strcpy(SERV_HOST, p+1);
  1794.                 }
  1795. #endif    /*!ISSERVER*/
  1796.                 quitwhile = ON;
  1797.                 break;
  1798.  
  1799.             /* doesn't matter if we overwrite the value in the client since the same value would have been picked up in main() anyway */
  1800.             case 'K' :
  1801.                 if (*(p + 1) == '\0') {/* space after - option */
  1802.                     if (argc <= 1) {
  1803.                         fprintf(stderr, "%s: the server port must follow the -C option\n", GProgname);
  1804.                         RETURN(usage());
  1805.                     }
  1806.                     argv ++;
  1807. #if    !ISSERVER
  1808.                     SERV_PORT = atoi(argv[0]);
  1809. #endif    /*!ISSERVER*/
  1810.                     argc --;
  1811.                 }
  1812. #if    !ISSERVER
  1813.                 else {
  1814.                     SERV_PORT = atoi(p+1);
  1815.                 }
  1816.                 if ((SERV_PORT < MIN_SERV_PORT) || (SERV_PORT > MAX_SERV_PORT)) {
  1817.                     fprintf(stderr, "Bad server port %d: must be in [%d, %d]: using default %d\n",
  1818.                         SERV_PORT, MIN_SERV_PORT, MAX_SERV_PORT, DEF_SERV_PORT);
  1819.                     SERV_PORT = DEF_SERV_PORT;
  1820.                 }
  1821. #endif    /*!ISSERVER*/
  1822.                 quitwhile = ON;
  1823.                 break;
  1824.             
  1825.             case 'C' :
  1826.                 CONTACT_SERVER = 1;
  1827.                 break;
  1828.  
  1829.             case 'a' :
  1830.                 PRINTATTR = 1;
  1831.                 break;
  1832.  
  1833.             case 'W':
  1834.                 wholefilescope = 1;
  1835.                 break;
  1836.  
  1837.             case 'z' :
  1838.                 UseFilters = 1;
  1839.                 break;
  1840.  
  1841.             case 'r' :
  1842.                 GRECURSIVE = 1;
  1843.                 break;
  1844.  
  1845.             case 'V' :
  1846.                 printf("\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  1847.                 RETURN(0);
  1848.  
  1849.             /* Must let 'f' and 'm' fall thru to default once multipatterns are done in agrep */
  1850.             case 'f' :
  1851.             case 'p' :
  1852.             case 'm' :
  1853.             case 'v' :
  1854.                 fprintf(stderr, "%s: illegal option: '-%c'\n", GProgname, c);
  1855.                 RETURN(usage());
  1856.                 break;
  1857.  
  1858.             case 'I' :
  1859.             case 'D' :
  1860.             case 'S' :
  1861.                 /* There is no space after these options */
  1862.                 agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1863.                 agrep_argv[agrep_argc][0] = '-';
  1864.                 strcpy(agrep_argv[agrep_argc] + 1, p);
  1865.                 agrep_argc ++;
  1866.                 quitwhile = ON;
  1867.                 break;
  1868.  
  1869.             case 'l':
  1870.                 GFILENAMEONLY = 1;
  1871.                 my_l_index = agrep_argc;
  1872.                 agrep_argv[agrep_argc] = (char *)my_malloc(4);
  1873.                 agrep_argv[agrep_argc][0] =  '-';
  1874.                 agrep_argv[agrep_argc][1] = c;
  1875.                 agrep_argv[agrep_argc][2] = '\0';
  1876.                 agrep_argc ++;
  1877.                 break;
  1878.  
  1879.             /*
  1880.              * Copy the set of options for agrep: put them in separate argvs
  1881.              * even if they are together after one '-' (easier to process).
  1882.              * These are agrep options which glimpse has to peek into.
  1883.              */
  1884.             default:
  1885.                 agrep_argv[agrep_argc] = (char *)my_malloc(16);
  1886.                 agrep_argv[agrep_argc][0] =  '-';
  1887.                 agrep_argv[agrep_argc][1] = c;
  1888.                 agrep_argv[agrep_argc][2] = '\0';
  1889.                 agrep_argc ++;
  1890.  
  1891.                 if (c == 'n') {
  1892.                     if (ByteLevelIndex) {
  1893.                         NOBYTELEVEL = 1;
  1894.                         fprintf(stderr, "Warning: -n is used with byte-level index: must SEARCH the files\n");
  1895.                     }
  1896.                 }
  1897.                 if (c == 't') GOUTTAIL = 1;
  1898.                 if (c == 'y') GNOPROMPT = 1;
  1899.                 else if (c == 'h') GNOFILENAME = 1;
  1900.                 else if (c == 'B') {
  1901.                     GBESTMATCH = 1;
  1902.                     my_B_index = agrep_argc - 1;
  1903.                 }
  1904.                 /* the following options are followed by a parameter */
  1905.                 else if ((c == 'e') || (c == 'd') || (c == 'L') || (c == 'k')) {
  1906.                     if (*(p + 1) == '\0') {/* space after - option */
  1907.                         if(argc <= 1) {
  1908.                             fprintf(stderr, "%s: the '-%c' option must have an argument\n", GProgname, c);
  1909.                             RETURN(usage());
  1910.                         }
  1911.                         argv++;
  1912.                         if ( (c == 'd') && ((D_length = strlen(argv[0])) > MAX_NAME_SIZE) ) {
  1913.                             fprintf(stderr, "%s: delimiter pattern too long (has > %d chars)\n", GProgname, MAX_NAME_SIZE);
  1914.                             RETURN(usage());
  1915.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1916.                         }
  1917.                         else if ((c == 'L') && ((GLIMITOUTPUT = atoi(argv[0])) < 0) ) {
  1918.                             fprintf(stderr, "%s: invalid output limit %s\n", GProgname, argv[0]);
  1919.                             RETURN(usage());
  1920.                         }
  1921.                         agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1922.                         strcpy(agrep_argv[agrep_argc], argv[0]);
  1923.                         if (c == 'd') {
  1924.                             preprocess_delimiter(argv[0], D_length, GD_pattern, &GD_length);
  1925.                             if (GOUTTAIL == 2) GOUTTAIL = 0;
  1926.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1927.                         }
  1928.                         argc--;
  1929.                     } else {
  1930.                         if ( (c == 'd') && ((D_length = strlen(p+1)) > MAX_NAME_SIZE) ) {
  1931.                             fprintf(stderr, "%s: delimiter pattern too long (has > %d chars)\n", GProgname, MAX_NAME_SIZE);
  1932.                             RETURN(usage());
  1933.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1934.                         }
  1935.                         else if ((c == 'L') && ((GLIMITOUTPUT = atoi(p+1)) < 0) ) {
  1936.                             fprintf(stderr, "%s: invalid output limit %s\n", GProgname, p+1);
  1937.                             RETURN(usage());
  1938.                         }
  1939.                         agrep_argv[agrep_argc] = (char *)my_malloc(strlen(p+1) + 2);
  1940.                         strcpy(agrep_argv[agrep_argc], p+1);
  1941.                         if (c == 'd') {
  1942.                             preprocess_delimiter(p+1, D_length-2, GD_pattern, &GD_length);
  1943.                             if (GOUTTAIL == 2) GOUTTAIL = 0;
  1944.                             /* Should this be RegionLimit if ByteLevelIndex? */
  1945.                         }
  1946.                     }
  1947.                     agrep_argc ++;
  1948. #if    DEBUG
  1949.                     fprintf(stderr, "%d = %s\n", agrep_argc, agrep_argv[agrep_argc - 1]);
  1950. #endif    /*DEBUG*/
  1951.                     quitwhile = ON;
  1952.                     if ((c == 'e') || (c == 'k')) foundpat = 1;
  1953.                 }
  1954.                 /* else it is something that glimpse doesn't know and agrep needs to look at */
  1955.  
  1956.                 break;    /* from default: */
  1957.  
  1958.             } /* switch(c) */
  1959.             p ++;
  1960.         }
  1961.     } /* while (--argc > 0 && (*++argv)[0] == '-') */
  1962.  
  1963. /* exitloop: */
  1964.  
  1965.     if ((GBESTMATCH == ON) && (MATCHFILE == ON) && (Only_first == ON))
  1966.         fprintf(stderr, "Warning: the number of matches may be incorrect when -B is used with -F.\n");
  1967.  
  1968.     if (GOUTTAIL) GOUTTAIL = 1;
  1969.  
  1970.     if (GNOFILENAME) {
  1971.         agrep_argv[my_A_index][1] = 'Z';    /* ignore the -A option */
  1972.     }
  1973.  
  1974.     if (argc > 0) {
  1975.         /* copy the rest of the options the pattern and the filenames if any verbatim */
  1976.         for (i=0; i<argc; i++) {
  1977.             if (agrep_argc >= MAX_ARGS) break;
  1978.             agrep_argv[agrep_argc] = (char *)my_malloc(strlen(argv[0]) + 2);
  1979.             strcpy(agrep_argv[agrep_argc], argv[0]);
  1980.             agrep_argc ++;
  1981.             argv ++;
  1982.         }
  1983.         if (!foundpat) argc --;
  1984.     }
  1985.  
  1986. #if    0
  1987.     for (j=0; j<agrep_argc; j++) printf("agrep_argv[%d] = %s\n", j, agrep_argv[j]);
  1988.     printf("argc = %d\n", argc);
  1989. #endif    /*0*/
  1990.  
  1991.     /*
  1992.      * Now perform the search by first looking at the index
  1993.      * and obtaining the files to search; and then search
  1994.      * them and output the result. If argc > 0, glimpse
  1995.      * runs as agrep: otherwise, it searches index, etc.
  1996.      */
  1997.  
  1998.     if (argc <= 0) {
  1999.         glimpse_call = 1;
  2000.         /* Initialize some data structures, read the index */
  2001.         if (GRECURSIVE == 1) {
  2002.             fprintf(stderr, "illegal option: '-r'\n");
  2003.             RETURN(usage());
  2004.         }
  2005.         num_terminals = 0;
  2006.         GParse = NULL;
  2007.         memset(terminals, '\0', sizeof(ParseTree) * MAXNUM_PAT);
  2008. #if    !ISSERVER
  2009.         if (-1 == read_index(indexdir)) RETURN(-1);
  2010. #endif    /*!ISSERVER*/
  2011.         WHOLEFILESCOPE = (WHOLEFILESCOPE || wholefilescope);
  2012.  
  2013.         if (ByteLevelIndex) {
  2014.             /* Must zero them here in addition to index search so that RETURN macro runs correctly */
  2015.             if ((src_offset_table == NULL) &&
  2016.                 ((src_offset_table = (struct offsets **)my_malloc(sizeof(struct offsets *) * OneFilePerBlock)) == NULL)) exit(2);
  2017.             memset(src_offset_table, '\0', sizeof(struct offsets *) * OneFilePerBlock);
  2018.             for (i=0; i<MAXNUM_PAT; i++) {
  2019.                 if ((multi_dest_offset_table[i] == NULL) &&
  2020.                     ((multi_dest_offset_table[i] = (struct offsets **)my_malloc(sizeof(struct offsets *) * OneFilePerBlock)) == NULL)) exit(2);
  2021.                 memset(multi_dest_offset_table[i], '\0', sizeof(struct offsets *) * OneFilePerBlock);
  2022.             }
  2023.         }
  2024.         read_filters(INDEX_DIR, UseFilters);
  2025.  
  2026.         if (glimpse_clientdied) RETURN(0);
  2027.         /* Now initialize agrep, set the options and get the actual pattern into GPattern */
  2028.         if ((GM = fileagrep_init(agrep_argc, agrep_argv, MAXPAT, GPattern)) <= 0) {
  2029.             /* this printf need not be there: agrep prints messages if error */
  2030.             RETURN(usage());
  2031.         }
  2032.         patindex = pattern_index;
  2033.         for (j=0; j<GM; j++) {
  2034.             if (GPattern[j] == '\\') j++;
  2035.             else if (test_indexable_char[GPattern[j]]) break;
  2036.         }
  2037.         if (j >= GM) {
  2038.             fprintf(stderr, "%s: pattern '%s' has no indexable characters: glimpse cannot search for it\n", GProgname, GPattern);
  2039.             RETURN(-1);
  2040.         }
  2041.  
  2042.         /* Split GPattern into individual boolean terms */
  2043.         if (split_pattern(GPattern, GM, APattern, terminals, &num_terminals, &GParse, StructuredIndex) <= 0) RETURN(-1);
  2044. #if    BG_DEBUG
  2045.         fprintf(debug, "GPattern = %s, APattern = %s, num_terminals = %d\n", GPattern, APattern, num_terminals);
  2046. #endif    /*BG_DEBUG*/
  2047.         if (foundattr) WHOLEFILESCOPE = 1;    /* makes no sense to search attribute=value expressions without WHOLEFILESCOPE */
  2048.         else if (!ComplexBoolean && !((long)GParse & AND_EXP)) WHOLEFILESCOPE = 0;    /* ORs can be done without WHOLEFILESCOPE */
  2049.         if (WHOLEFILESCOPE <= 0) agrep_argv[my_b_index][1] = 'Z';
  2050.         if (!ComplexBoolean && ((long)GParse & AND_EXP) && (my_l_index != -1)) agrep_argv[my_l_index][1] = 'Z';
  2051.  
  2052.         /* Now re-initialize agrep_argv with APattern instead of GPattern */
  2053.         my_free(agrep_argv[patindex], 0);
  2054.         AM=strlen(APattern);
  2055.         agrep_argv[patindex] = (char *)my_malloc(AM + 2);
  2056.         strcpy(agrep_argv[patindex], APattern);
  2057.  
  2058.         /*
  2059.          * Copy the agrep-options that are relevant to index search into
  2060.          * index_argv (see man-pages for which options are relevant).
  2061.          * Also, adjust patindex whenever options are skipped over.
  2062.          * NOTE: agrep_argv does NOT contain two options after one '-'.
  2063.          */
  2064.         index_argc = 0;
  2065.         for (j=0; j<agrep_argc; j++) {
  2066.             if (agrep_argv[j][0] == '-') {
  2067.                 if ((agrep_argv[j][1] == 'c') || (agrep_argv[j][1] == 'h') || (agrep_argv[j][1] == 'l') || (agrep_argv[j][1] == 'n') ||
  2068.                     (agrep_argv[j][1] == 's') || (agrep_argv[j][1] == 't') || (agrep_argv[j][1] == 'G') || (agrep_argv[j][1] == 'O') ||
  2069.                     (agrep_argv[j][1] == 'b') || (agrep_argv[j][1] == 'i')) {
  2070.                     patindex --;
  2071.                     continue;
  2072.                 }
  2073.                 if ((agrep_argv[j][1] == 'd') || (agrep_argv[j][1] == 'L')) {    /* skip over the argument too */
  2074.                     j++;
  2075.                     patindex -= 2;
  2076.                     continue;
  2077.                 }
  2078.                 if ((agrep_argv[j][1] == 'e') || (agrep_argv[j][1] == 'm')) {
  2079.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  2080.                     index_argc ++; j++;
  2081.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  2082.                     if (agrep_argv[j-1][1] == 'm') patbufpos = index_argc;    /* where to put the patbuf if fast-boolean by mgrep() */
  2083.                     index_argc ++;
  2084.                 }
  2085.                 else {    /* No arguments: just copy THAT option: maybe, change some options */
  2086.                     strcpy(index_argv[index_argc], agrep_argv[j]);
  2087.                     if (agrep_argv[j][1] == 'A') index_argv[index_argc][1] = 'h';
  2088.                     else if (agrep_argv[j][1] == 'x') index_argv[index_argc][1] = 'w';
  2089.                     index_argc++;
  2090.                 }
  2091.             }
  2092.             else {    /* This is either the pattern itself or a filename */
  2093.                 strcpy(index_argv[index_argc], agrep_argv[j]);
  2094.                 index_argc++;
  2095.             }
  2096.         }
  2097.         sprintf(index_argv[index_argc], "%s", INDEX_FILE);
  2098.         index_argc ++;
  2099. #if    0
  2100.         for (j=0; j<index_argc; j++) printf("index_argv[%d] = %s\n", j, index_argv[j]);
  2101.         printf("patindex = %d\n", patindex);
  2102. #endif    /*0*/
  2103.  
  2104.         /* Search the index and process index-search-only options; Worry about file-pattern */
  2105.         ret = search_index(GParse);
  2106.         if (ret <= 0) RETURN(-1);
  2107.         num_blocks=0;
  2108.         if (OneFilePerBlock) {
  2109.             for(iii=0; iii<round(OneFilePerBlock, 8*sizeof(int)); iii++) {
  2110.                 if (src_index_set[iii] == 0) continue;
  2111.                 for (jjj=0; jjj < 8*sizeof(int); jjj++)
  2112.                     if (src_index_set[iii] & mask_int[jjj])
  2113.                         num_blocks ++;
  2114.             }
  2115.             if (num_blocks > OneFilePerBlock) num_blocks = OneFilePerBlock;    /* roundoff */
  2116.         }
  2117.         else {
  2118.             GNumpartitions = get_table(P_TABLE, p_table, MAX_PARTITION, 0);        /* Get partitions before calling get_filenames() */
  2119.             for (iii=0; iii<MAX_PARTITION; iii++)
  2120.                 if (src_index_set[iii]) num_blocks++;
  2121.         }
  2122.         if (num_blocks <= 0) RETURN (0);
  2123.         if ((src_index_set[REAL_PARTITION - 1] == 1) && !Only_first && !OPTIMIZEBYTELEVEL) {
  2124.             fprintf(stderr, "Warning: pattern has words present in the stop-list: must SEARCH the files\n");
  2125.         }
  2126.         /* if just the NOBYTELEVEL flag is set, then it is an optimization which glimpse does and user need not be warned */
  2127. #if    DEBUG
  2128.         fprintf(stderr, "--> search=%d optimize=%d times=%d all=%d blocks=%d len=%d pat=%s scope=%d\n",
  2129.             NOBYTELEVEL, OPTIMIZEBYTELEVEL, src_index_set[REAL_PARTITION - 2], src_index_set[REAL_PARTITION - 1], num_blocks, strlen(APattern), APattern, WHOLEFILESCOPE);
  2130. #endif    /*DEBUG*/
  2131.         dummypat[0] = '\0';
  2132.         if (!MATCHFILE)    {    /* the argc,argv don't matter */
  2133.             get_filenames(src_index_set, 0, NULL, dummylen, dummypat, OneFilePerBlock);
  2134.  
  2135.             if (Only_first) { /* search the index only */
  2136.                 fprintf(stderr, "There are matches to %d out of %d %s\n", num_blocks, (OneFilePerBlock > 0) ? OneFilePerBlock : GNumpartitions, (OneFilePerBlock > 0) ? "files" : "blocks");
  2137.                 if (OneFilePerBlock && (num_blocks > 0)) {
  2138.                     char    cc[8];
  2139.                     cc[0] = 'y';
  2140. #if    !ISSERVER
  2141.                     if (!GNOPROMPT) {
  2142.                         fprintf(stderr, "Do you want to see the file names? (y/n)");
  2143.                         fgets(cc, 4, stdin);
  2144.                     }
  2145. #endif    /*!ISSERVER*/
  2146.                     if (cc[0] == 'y') {
  2147.                         for (jjj=0; jjj<GNumfiles; jjj++)
  2148.                             printf("%s\n", GTextfiles[jjj]);
  2149.                     }
  2150.                 }
  2151.                 RETURN(0);
  2152.             }
  2153.             if (!OneFilePerBlock) searchpercent = num_blocks*100/GNumpartitions;
  2154.             else searchpercent = num_blocks * 100 / OneFilePerBlock;
  2155. #if    BG_DEBUG
  2156.             fprintf(debug, "searchpercent = %d, num_blocks = %d\n", searchpercent, num_blocks);
  2157. #endif    /*BG_DEBUG*/
  2158. #if    !ISSERVER
  2159.             if (!GNOPROMPT && (searchpercent > MAX_SEARCH_PERCENT)) {
  2160.                 char    cc[8];
  2161.                 cc[0] = 'y';
  2162.                 fprintf(stderr, "Your query may search about %d%% of the total space! Continue? (y/n)", searchpercent); 
  2163.                 fgets(cc, 4, stdin);
  2164.                 if (cc[0] != 'y') RETURN(0);
  2165.                 if (ByteLevelIndex && (searchpercent > DEF_MAX_INDEX_PERCENT)) NOBYTELEVEL = 1;
  2166.             }
  2167. #endif    /*!ISSERVER*/
  2168.         }
  2169.         else {    /* set up the right options for -F in index_argv/index_argc itself since they will no longer be used */
  2170.             index_argc=0;
  2171.             strcpy(index_argv[0], GProgname);
  2172.  
  2173.             /* adding the -h option, which is safer for -F */
  2174.             index_argc ++;
  2175.             index_argv[index_argc][0] =  '-';
  2176.             index_argv[index_argc][1] = 'h';
  2177.             index_argv[index_argc][2] = '\0';
  2178.             index_argc ++;
  2179.  
  2180.             /* new code: bgopal, Feb/8/94: deleted udi's code here */
  2181.             j = 0;
  2182.             while (FileOpt[j] == '-') {
  2183.                 j++;
  2184.                 while ((FileOpt[j] != ' ') && (FileOpt[j] != '\0') && (FileOpt[j] != '\n')) {
  2185.                     if (j >= MAX_ARGS - 1) {
  2186.                         fprintf(stderr, "%s: too many options after -F: %s\n", GProgname, FileOpt);
  2187.                         RETURN(usage());
  2188.                     }
  2189.                     index_argv[index_argc][0] =  '-';
  2190.                     index_argv[index_argc][1] = FileOpt[j];
  2191.                     index_argv[index_argc][2] = '\0';
  2192.                     index_argc ++;
  2193.                     j++;
  2194.                 }
  2195.                 if ((FileOpt[j] == '\0') || (FileOpt[j] == '\n')) break;
  2196.                 if ((FileOpt[j] == ' ') && (FileOpt[j-1] == '-')) {
  2197.                     fprintf(stderr, "%s: illegal option: '-' after -F\n", GProgname);
  2198.                     RETURN(usage());
  2199.                 }
  2200.                 else if (FileOpt[j] == ' ') while(FileOpt[j] == ' ') j++;
  2201.             }
  2202.             while(FileOpt[j] == ' ') j++;
  2203.  
  2204.             fileopt_length = strlen(FileOpt);
  2205.             strncpy(index_argv[index_argc],FileOpt+j,fileopt_length-j);
  2206.             index_argv[index_argc][fileopt_length-j] = '\0';
  2207.             index_argc++;
  2208.             my_free(FileOpt, MAXFILEOPT);
  2209.             FileOpt = NULL;
  2210.  
  2211. #if    BG_DEBUG
  2212.             fprintf(debug, "pattern to check with -F = %s\n",index_argv[index_argc-1]);
  2213. #endif    /*BG_DEBUG*/
  2214. #if    DEBUG
  2215.             fprintf(stderr, "-F : ");
  2216.             for (jj=0; jj < index_argc; jj++) 
  2217.                 fprintf(stderr, " %s ",index_argv[jj]);
  2218.             fprintf(stderr, "\n");
  2219. #endif    /*DEBUG*/
  2220.             fflush(stdout);
  2221.             get_filenames(src_index_set, index_argc, index_argv, dummylen, dummypat, OneFilePerBlock);
  2222.  
  2223.             /* Assume #files per partitions is appx constant */
  2224.             if (OneFilePerBlock) num_blocks = GNumfiles;
  2225.             else num_blocks = GNumfiles * GNumpartitions / p_table[GNumpartitions - 1];
  2226.             if (Only_first) { /* search the index only */
  2227.                 fprintf(stderr, "There are matches to %d out of %d %s\n", num_blocks, (OneFilePerBlock > 0) ? OneFilePerBlock : GNumpartitions, (OneFilePerBlock > 0) ? "files" : "blocks");
  2228.                 if (OneFilePerBlock && (num_blocks > 0)) {
  2229.                     char    cc[8];
  2230.                     cc[0] = 'y';
  2231. #if    !ISSERVER
  2232.                     if (!GNOPROMPT) {
  2233.                         fprintf(stderr, "Do you want to see the file names? (y/n)");
  2234.                         fgets(cc, 4, stdin);
  2235.                     }
  2236. #endif    /*!ISSERVER*/
  2237.                     if (cc[0] == 'y') {
  2238.                         for (jjj=0; jjj<GNumfiles; jjj++)
  2239.                             printf("%s\n", GTextfiles[jjj]);
  2240.                     }
  2241.                 }
  2242.                 RETURN(0);
  2243.             }
  2244.             if (OneFilePerBlock) searchpercent = GNumfiles * 100 / OneFilePerBlock;
  2245.             else searchpercent = GNumfiles * 100 / p_table[GNumpartitions - 1];
  2246. #if    BG_DEBUG
  2247.             fprintf(debug, "searchpercent = %d, num_files = %d\n", searchpercent, p_table[GNumpartitions - 1]);
  2248. #endif    /*BG_DEBUG*/
  2249. #if    !ISSERVER
  2250.             if (!GNOPROMPT && (searchpercent > MAX_SEARCH_PERCENT)) {
  2251.                 char    cc[8];
  2252.                 cc[0] = 'y';
  2253.                 fprintf(stderr, "Your query may search about %d%% of the total space! Continue? (y/n)", searchpercent); 
  2254.                 fgets(cc, 4, stdin);
  2255.                 if (cc[0] != 'y') RETURN(0);
  2256.                 if (ByteLevelIndex && (searchpercent > DEF_MAX_INDEX_PERCENT)) NOBYTELEVEL = 1;
  2257.             }
  2258. #endif    /*!ISSERVER*/
  2259.         }
  2260.  
  2261.         /* Replace -B by the number of errors if best-match */
  2262.         if (GBESTMATCH && (my_B_index >= 0)) {
  2263.             sprintf(&agrep_argv[my_B_index][1], "%d", bestmatcherrors);
  2264. #if    BG_DEBUG
  2265.             fprintf(debug, "Changing -B to -%d\n", bestmatcherrors);
  2266. #endif    /*BG_DEBUG*/
  2267.         }
  2268.         agrep_argv[my_M_index][1] = 'Z';
  2269.         agrep_argv[my_P_index][1] = 'Z';
  2270.         if (!ComplexBoolean && ((long)GParse & AND_EXP) && (my_l_index != -1) && !WHOLEFILESCOPE) agrep_argv[my_l_index][1] = 'l';
  2271.  
  2272.         if (GNumfiles <= 0) RETURN(0);
  2273.         if (glimpse_clientdied) RETURN(0);
  2274.         /* must reinitialize since the above agrep calls for index-search ruined the real options: it is required EVEN IF ByteLevelIndex */
  2275.         AM = fileagrep_init(agrep_argc, agrep_argv, MAXPAT, APattern);
  2276.         /* do acutal search with postfiltering if structured query */
  2277.         if (WHOLEFILESCOPE <= 0) {
  2278.             if (!UseFilters) {
  2279.                 if (!ByteLevelIndex || NOBYTELEVEL) {
  2280.                     fileagrep_search(AM, APattern, GNumfiles, GTextfiles, 0, stdout);
  2281.                 }
  2282.                 else {
  2283.                     for (i=0; i<GNumfiles; i++) {
  2284.                         SetCurrentFileName = 1;
  2285.                         strcpy(CurrentFileName, GTextfiles[i]);
  2286.                         if (stat(CurrentFileName, &file_stat_buf) == -1) continue;
  2287.                         if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2288.                             /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2289.                             free_list(&src_offset_table[GFileIndex[i]]);
  2290.                             first_search = 1;
  2291.                             if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) gnum_of_matched += ret;
  2292.                         }
  2293.                         else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GFileIndex[i], src_offset_table, stdout)) > 0) gnum_of_matched += ret;
  2294.                         SetCurrentFileName = 0;
  2295.                         if (GLIMITOUTPUT > 0) {
  2296.                             if (GLIMITOUTPUT <= gnum_of_matched) break;
  2297.                             LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2298.                         }
  2299.                          if ((ret < 0) && REGEX && (WORDBOUND || DELIMITER)) break;
  2300.                         if (glimpse_clientdied) break;
  2301.                         fflush(stdout);
  2302.                     }
  2303.                 }
  2304.             }
  2305.             else {
  2306.                 sprintf(outname[0], "%s/.glimpse_apply.%d", TEMP_DIR, getpid());
  2307.                 for (i=0; i<GNumfiles; i++) {
  2308.                     if (apply_filter(GTextfiles[i], outname[0]) == 1) {
  2309.                         SetCurrentFileName = 1;
  2310.                         strcpy(CurrentFileName, GTextfiles[i]);
  2311.                         if (stat(CurrentFileName, &file_stat_buf) == -1) continue;
  2312.                         if (!ByteLevelIndex || NOBYTELEVEL || (file_stat_buf.st_mtime > index_stat_buf.st_mtime)) {
  2313.                             first_search = 1;
  2314.                             if ((ret = fileagrep_search(AM, APattern, 1, outname, 0, stdout)) > 0) gnum_of_matched += ret;
  2315.                         }
  2316.                         else {
  2317.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2318.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2319.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2320.                                 first_search = 1;
  2321.                                 if ((ret = fileagrep_search(AM, APattern, 1, outname, 0, stdout)) > 0) gnum_of_matched += ret;
  2322.                             }
  2323.                             else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, outname[0], GFileIndex[i], src_offset_table, stdout)) > 0) gnum_of_matched += ret;
  2324.                         }
  2325.                         unlink(outname[0]);
  2326.                         SetCurrentFileName = 0;
  2327.                     }
  2328.                     else {
  2329.                         if (!ByteLevelIndex || NOBYTELEVEL) {
  2330.                             first_search = 1;
  2331.                             if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) gnum_of_matched += ret;
  2332.                         }
  2333.                         else {
  2334.                             SetCurrentFileName = 1;
  2335.                             strcpy(CurrentFileName, GTextfiles[i]);
  2336.                             if (stat(CurrentFileName, &file_stat_buf) == -1) continue;
  2337.                             if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2338.                                 /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2339.                                 free_list(&src_offset_table[GFileIndex[i]]);
  2340.                                 first_search = 1;
  2341.                                 if ((ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, stdout)) > 0) gnum_of_matched += ret;
  2342.                             }
  2343.                             else if ((ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GFileIndex[i], src_offset_table, stdout)) > 0) gnum_of_matched += ret;
  2344.                             SetCurrentFileName = 0;
  2345.                         }
  2346.                     }
  2347.                     if (GLIMITOUTPUT > 0) {
  2348.                         if (GLIMITOUTPUT <= gnum_of_matched) break;
  2349.                         LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2350.                     }
  2351.                      if ((ret < 0) && REGEX && (WORDBOUND || DELIMITER)) break;
  2352.                     if (glimpse_clientdied) break;
  2353.                     fflush(stdout);
  2354.                 }
  2355.             }
  2356.         }
  2357.         else {    /* Filters do not apply here */
  2358.             FILE    *tmpfp = NULL;    /* to store structured query-search output */
  2359.                         int     OLDLIMITOUTPUT; /* don't use LIMITOUTPUT for search: only for filtering=identify_region(): agrep NEVER changes LIMITOUTPUT */
  2360.  
  2361.             for (i=0; i<GNumfiles; i++) {
  2362.                 OLDLIMITOUTPUT = LIMITOUTPUT;
  2363.                 LIMITOUTPUT = 0;
  2364.                 if ((tmpfp = fopen(tempfile, "w")) == NULL) {
  2365.                     fprintf(stderr, "%s: cannot open for writing: %s, errno=%d\n", GProgname, tempfile, errno);
  2366.                     RETURN(usage());
  2367.                 }
  2368.                 SetCurrentFileName = 1;
  2369.                 strcpy(CurrentFileName, GTextfiles[i]);
  2370.                 if (!ByteLevelIndex || NOBYTELEVEL) {
  2371.                     first_search = 1;
  2372.                     ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2373.                 }
  2374.                 else {
  2375.                     if (stat(CurrentFileName, &file_stat_buf) == -1) {
  2376.                         fclose(tmpfp);
  2377.                         continue;
  2378.                     }
  2379.                     if (file_stat_buf.st_mtime > index_stat_buf.st_mtime) {
  2380.                         /* fprintf(stderr, "Warning: file modified after indexing: must SEARCH %s\n", CurrentFileName); */
  2381.                         free_list(&src_offset_table[GFileIndex[i]]);
  2382.                         first_search = 1;
  2383.                         ret = fileagrep_search(AM, APattern, 1, >extfiles[i], 0, tmpfp);
  2384.                     }
  2385.                     else ret = glimpse_search(AM, APattern, GD_length, GD_pattern, GTextfiles[i], GFileIndex[i], src_offset_table, tmpfp);
  2386.                 }
  2387.                 SetCurrentFileName = 0;
  2388.                 fflush(tmpfp);
  2389.                 fclose(tmpfp);
  2390.                 tmpfp = NULL;
  2391.                  if ((ret < 0) && REGEX && (WORDBOUND || DELIMITER)) break;
  2392. #if    DEBUG
  2393.                 printf("done search\n");
  2394.                 fflush(stdout);
  2395. #endif    /*DEBUG*/
  2396.                 LIMITOUTPUT = OLDLIMITOUTPUT;
  2397.                 ret = filter_output(GTextfiles[i], tempfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, StructuredIndex);
  2398.                 gnum_of_matched += (ret > 0) ? ret : 0;
  2399.                 if (GLIMITOUTPUT > 0) {
  2400.                     if (GLIMITOUTPUT <= gnum_of_matched) break;
  2401.                     LIMITOUTPUT = GLIMITOUTPUT - gnum_of_matched;
  2402.                 }
  2403.                 if (glimpse_clientdied) break;
  2404.                 fflush(stdout);
  2405.             }
  2406.         }
  2407.  
  2408.         RETURN(0);
  2409.     }
  2410.     else { /* argc > 0: simply call agrep */
  2411. #if    DEBUG
  2412.         for (i=0; i<agrep_argc; i++)
  2413.             printf("agrep_argv[%d] = %s\n", i, agrep_argv[i]);
  2414. #endif    /*DEBUG*/
  2415.         i = fileagrep(oldargc, oldargv, 0, stdout);
  2416.         RETURN(i);
  2417.     }
  2418. }
  2419. /* end of process_query() */
  2420.  
  2421. /*
  2422.  * Simple function to remove the non-existent files from the set of
  2423.  * files passed onto agrep for search. These are the files which got
  2424.  * DELETED after the index was built (but a fresh index was NOT built).
  2425.  * Redundant since agrep opens them anyway and stat is as bad as open.
  2426.  */
  2427. int
  2428. purge_filenames(filenames, num)
  2429.     CHAR    **filenames;
  2430.     int    num;
  2431. {
  2432.     struct stat    buf;
  2433.     int        i, j;
  2434.     int        newnum = num;
  2435.     int        ret;
  2436.  
  2437.     for (i=0; i<newnum; i++) {
  2438.         if (-1 == (ret = stat(filenames[i], &buf))) {
  2439. #if    BG_DEBUG
  2440.             fprintf(debug, "stat on %s = %d\n", filenames[i], ret);
  2441. #endif    /*BG_DEBUG*/
  2442.             my_free(filenames[i], 0);
  2443.             for (j=i; j<newnum-1; j++)
  2444.                 filenames[j] = filenames[j+1];
  2445.             filenames[j] = NULL;
  2446.             newnum --;
  2447.             i--;    /* offset the increment: start from current */
  2448.         }
  2449.     }
  2450.  
  2451. #if    BG_DEBUG
  2452.     fprintf(debug, "Old numfiles=%d\tNew numfiles=%d\n", num, newnum);
  2453.     for (i=0; i<newnum; i++)
  2454.         fprintf(debug, "file %d = %s\n", i, filenames[i]);
  2455. #endif    /*BG_DEBUG*/
  2456.     return newnum;
  2457. }
  2458.  
  2459. CHAR filter_buf[BLOCKSIZE + MAXPAT*2];
  2460.  
  2461. /* returns #of bytes stripped off */
  2462. int getbyteoff(buf, pbyteoff)
  2463.     CHAR    *buf;
  2464.     int    *pbyteoff;
  2465. {
  2466.     CHAR    temp[32];
  2467.     int    i = 0;
  2468.  
  2469.     while (isdigit(*buf) && (i<32)) temp[i++] = *buf++;
  2470.     if ((*buf != '=') || (*(buf + 1) != ' ')) return -1;
  2471.     temp[i] = '\0';
  2472.     *pbyteoff = atoi(temp);
  2473.     return i+2;
  2474. }
  2475.  
  2476. /*
  2477.  * Filter the output in infile:
  2478.  *
  2479.  * -- get the matched line/record-s using GD_pattern, GD_length and GOUTAIL
  2480.  * -- call identify regions using matched line/record's byte offset
  2481.  * -- collect patterns corr. to that attribute into a new pattern (in split_pat itself)
  2482.  * -- see if one of them matches that line/record using memagrep
  2483.  * -- if so, output that line/record onto stdout
  2484.  */
  2485. int
  2486. filter_output(infile, outfile, GParse, GD_pattern, GD_length, GOUTTAIL, nullfp, num_attr)
  2487.     char    *infile;
  2488.     char    *outfile;
  2489.     ParseTree *GParse;
  2490.     CHAR    GD_pattern[];
  2491.     int    GD_length[];
  2492.     int    GOUTTAIL;
  2493.     FILE    *nullfp;
  2494.     int    num_attr;
  2495. {
  2496.     FILE    *outfp;
  2497.     FILE    *displayfp = NULL;
  2498.     FILE    *storefp = NULL;
  2499.     int    num_read;
  2500.     int    residue = 0;
  2501.     int    byteoff;
  2502.     int    attribute;
  2503.     int    i, ii;    /* i is forloop index, ii is booleaneval index */
  2504.     CHAR    *final_end;
  2505.     CHAR    *current_end;
  2506.     CHAR    *current_begin;
  2507.     CHAR    *previous_begin;
  2508.     int    skiplen;
  2509.     char    s[MAX_LINE_LEN];
  2510.     CHAR    c1, c2;
  2511.     int    printed, numprinted = 0;    /* returns number of printed records if successful in matching the pattern in the object infile */
  2512.     char    *attrname;
  2513.     int    success = 0;    /* do we print the stored output or not */
  2514.  
  2515. #if    BG_DEBUG
  2516.     printf("INFILE=%s\n", infile);
  2517.     printf("OUTFILE\n");
  2518.     sprintf(s, "cat %s\n", outfile);
  2519.     system(s);
  2520. #endif    /*BG_DEBUG*/
  2521.     if ((outfp = fopen(outfile, "r")) == NULL) return 0;
  2522.     if (StructuredIndex && (-1 == region_create(infile))) {
  2523.         fclose(outfp);
  2524.         return 0;
  2525.     }
  2526.     if (ComplexBoolean || ((long)GParse & AND_EXP)) {
  2527.         sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  2528.         if ((displayfp = storefp = fopen(s, "w")) == NULL) {
  2529.             if (StructuredIndex) region_destroy();
  2530.             fclose(outfp);
  2531.             return 0;
  2532.         }
  2533.     }
  2534.     else {
  2535.         displayfp = stdout;
  2536.         /* cannot come to filter_output in this case! */
  2537.     }
  2538.     memset(matched_terminals, '\0', num_terminals);
  2539.  
  2540.     while ( ( (num_read = fread(filter_buf + residue, 1, BLOCKSIZE - residue, outfp)) > 0) || (residue > 0)) {
  2541.         if (num_read <= 0) {
  2542.             final_end = filter_buf + residue;
  2543.             num_read = residue;
  2544.             residue = 0;
  2545.         }
  2546.         else {
  2547.             num_read += residue;
  2548.             final_end = (CHAR *)backward_delimiter(filter_buf + num_read, filter_buf, GD_pattern, GD_length, GOUTTAIL);
  2549.             residue = filter_buf + num_read - final_end;
  2550.         }
  2551. #if    DEBUG
  2552.         fprintf(stderr, "filter_buf=%x final_end=%x residue=%x last_chars=%c%c%c num_read=%x\n",
  2553.             filter_buf, final_end, residue, *(final_end-2), *(final_end-1), *(final_end), num_read);
  2554. #endif    /*DEBUG*/
  2555.  
  2556.         current_begin = previous_begin = filter_buf;
  2557.         current_end = (CHAR *)forward_delimiter(filter_buf, filter_buf + num_read, GD_pattern, GD_length, GOUTTAIL);    /* skip over prefixes like filename */
  2558.         if (!GOUTTAIL) current_end = (CHAR *)forward_delimiter((long)current_end + GD_length, final_end, GD_pattern, GD_length, GOUTTAIL);
  2559.  
  2560.         while (current_end <= final_end) {
  2561.             previous_begin = current_begin;
  2562.             /* look for %d= */
  2563.             byteoff = -1;
  2564.             while (current_begin < current_end) {
  2565.                 if (isdigit(*current_begin)) {
  2566.                     skiplen = getbyteoff(current_begin, &byteoff);
  2567. #if    BG_DEBUG
  2568.                     fprintf(debug, "byteoff=%d skiplen=%d\n", byteoff, skiplen);
  2569. #endif    /*BG_DEBUG*/
  2570.                     if ((skiplen < 0) || (byteoff < 0)) {
  2571.                         current_begin ++;
  2572.                         continue;
  2573.                     }
  2574.                     else break;
  2575.                 }
  2576.                 else current_begin ++;
  2577.             }
  2578. #if    DEBUG
  2579.             printf("current_begin=%x current_end=%x final_end=%x residue=%x num_read=%x\n", current_begin, current_end, final_end, residue, num_read);
  2580. #endif    /*DEBUG*/
  2581.  
  2582. #if    DEBUG
  2583.             printf("byteoff=%d skiplen=%d\n", byteoff, skiplen);
  2584. #endif    /*DEBUG*/
  2585.             if ((skiplen < 0) || (byteoff < 0)) {    /* output the whole line as it is: there is nothing to strip (e.g., -l) */
  2586.                 fwrite(previous_begin, 1, current_end-previous_begin, displayfp);
  2587.                 numprinted ++;
  2588.             }
  2589.             else if ( (num_attr <= 0) || (((attribute = region_identify(byteoff, 0)) < num_attr) && (attribute >= 0)) ) {
  2590.                 /* prefix is from previous_begin to current_begin. Skip skiplen from current_begin. Rest until current_end is valid output */
  2591.                 if (num_attr <= 0) attribute = 0;
  2592. #if    BG_DEBUG
  2593.                 fprintf(debug, "region@%d=%d\n", byteoff, attribute);
  2594. #endif    /*BG_DEBUG*/
  2595.                 c1 = *(current_begin + skiplen - 1);
  2596.                 c2 = *(current_end + 1);
  2597.                 printed = 0;
  2598.  
  2599.                 if (!success) {
  2600.                     if (ComplexBoolean) {
  2601.                         success = eval_tree(GParse, matched_terminals);
  2602.                     }
  2603.                     else {
  2604.                         if ((long)GParse & AND_EXP) {
  2605.                             success = 0;
  2606.                             for (ii=0; ii<num_terminals; ii++) {
  2607.                                 if (!matched_terminals[ii]) break;
  2608.                             }
  2609.                             if (ii >= num_terminals) success = 1;
  2610.                         }
  2611.                         else {
  2612.                             success = 0;
  2613.                             /* cannot come to filter_output in this case! */
  2614.                         }
  2615.                     }
  2616.                 }
  2617.  
  2618.                 /*
  2619.                  * Search for the value in the terminals array corr. to the matched attribute in the buffer and set matched_terminals.
  2620.                  * Cannot skip evaluating midway once expression is satisfied since I have to store the output in the temp file anyway.
  2621.                  */
  2622.                 if (!success) for (i=0; i<num_terminals; i++) {
  2623.                     if (matched_terminals[i]) {    /* success is still 0 otherwise wouldn't have (re)entered the for loop */
  2624.                         if (!((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) && !printed) {    /* see if it was useful later */
  2625.                             fwrite(previous_begin, 1, current_begin - previous_begin, displayfp);
  2626.                             if (PRINTATTR) fprintf(displayfp, "%s# ",
  2627.                                 (attrname = attr_id_to_name(attribute)) == NULL ? "(null)" : attrname);
  2628.                             fwrite(current_begin + skiplen, 1, current_end - current_begin - skiplen, displayfp);
  2629.                             printed = 1;
  2630.                             numprinted ++;
  2631.                         }
  2632.                         continue;
  2633.                     }
  2634.  
  2635.                     if ((terminals[i].data.leaf.attribute == 0)  || (terminals[i].data.leaf.attribute == attribute)) {
  2636.                         *(current_begin + skiplen - 1) = '\n';
  2637.                         *(current_end + 1) = '\n';
  2638.                         if (memagrep_search(    strlen(terminals[i].data.leaf.value), terminals[i].data.leaf.value,
  2639.                                     current_end - current_begin - skiplen + 1, current_begin + skiplen - 1,
  2640.                                     0, nullfp) > 0) {
  2641. #if    0
  2642.                             *(current_end + 1) = '\0';
  2643.                             printf("--> search succeeded for %s in %s\n", terminals[i].data.leaf.value, previous_begin);
  2644. #endif    /*0*/
  2645.                             *(current_begin + skiplen - 1) = c1;
  2646.                             *(current_end + 1) = c2;
  2647.                             matched_terminals[i] = 1;
  2648.  
  2649.                             if (!success) {
  2650.                                 if (ComplexBoolean) {
  2651.                                     success = eval_tree(GParse, matched_terminals);
  2652.                                 }
  2653.                                 else {
  2654.                                     if ((long)GParse & AND_EXP) {
  2655.                                         success = 0;
  2656.                                         for (ii=0; ii<num_terminals; ii++) {
  2657.                                             if (!matched_terminals[ii]) break;
  2658.                                         }
  2659.                                         if (ii >= num_terminals) success = 1;
  2660.                                     }
  2661.                                     else {
  2662.                                         success = 0;
  2663.                                         /* cannot come to filter_output in this case! */
  2664.                                     }
  2665.                                 }
  2666.                             }
  2667.  
  2668.                             if (success) break;
  2669.  
  2670.                             if (!((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) && !printed) {    /* see if it was useful later */
  2671.                                 fwrite(previous_begin, 1, current_begin - previous_begin, displayfp);
  2672.                                 if (PRINTATTR) fprintf(displayfp, "%s# ",
  2673.                                     (attrname = attr_id_to_name(attribute)) == NULL ? "(null)" : attrname);
  2674.                                 fwrite(current_begin + skiplen, 1, current_end - current_begin - skiplen, displayfp);
  2675.                                 printed = 1;
  2676.                                 numprinted ++;
  2677.                             }
  2678.                         }
  2679.                         else {
  2680. #if    0
  2681.                             *(current_end + 1) = '\0';
  2682.                             printf("--> search failed for %s in %s\n", terminals[i].data.leaf.value, previous_begin);
  2683. #endif    /*0*/
  2684.                             *(current_begin + skiplen - 1) = c1;
  2685.                             *(current_end + 1) = c2;
  2686.                         }
  2687.                     }
  2688.                 }
  2689.  
  2690.                 if (success) {    /* dump out everything in store, then just output everything without searching */
  2691.                     if (GFILENAMEONLY) {    /* all other output options are useless since they all deal with the MATCHED line */
  2692.                         fprintf(stdout, "%s\n", infile);
  2693.                         if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  2694.                         storefp = NULL;
  2695.                         goto unlink_and_quit;
  2696.                     }
  2697.                     else if (storefp != NULL) {
  2698.                         fflush(storefp);
  2699.                         fclose(storefp);
  2700.                         sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  2701.                         if ((storefp = fopen(s, "r")) != NULL) {
  2702.                             while (fgets(s, MAX_LINE_LEN, storefp) != NULL) fputs(s, stdout);
  2703.                             fclose(storefp);
  2704.                         }
  2705.                         storefp = NULL;
  2706.                         displayfp = stdout;
  2707.                     }
  2708.  
  2709.                     if (!((LIMITOUTPUT > 0) && (numprinted >= LIMITOUTPUT)) && !printed) {
  2710.                         fwrite(previous_begin, 1, current_begin - previous_begin, displayfp);
  2711.                         if (PRINTATTR) fprintf(displayfp, "%s# ",
  2712.                             (attrname = attr_id_to_name(attribute)) == NULL ? "(null)" : attrname);
  2713.                         fwrite(current_begin + skiplen, 1, current_end - current_begin - skiplen, displayfp);
  2714.                         printed = 1;
  2715.                         numprinted ++;
  2716.                     }
  2717.                 }
  2718.             }
  2719.             if (glimpse_clientdied) break;
  2720.             if (current_end >= final_end) break;
  2721.             current_begin = current_end;
  2722.             if (!GOUTTAIL) current_end = (CHAR *)forward_delimiter((long)current_end + GD_length, final_end, GD_pattern, GD_length, GOUTTAIL);
  2723.             else current_end = (CHAR *)forward_delimiter(current_end, final_end, GD_pattern, GD_length, GOUTTAIL);
  2724.         }
  2725.         if (residue > 0) memcpy(filter_buf, final_end, residue);
  2726.     }
  2727.  
  2728.     if (success) goto unlink_and_quit;
  2729.  
  2730.     if (ComplexBoolean) {
  2731.         success = eval_tree(GParse, matched_terminals);
  2732.     }
  2733.     else {
  2734.         if ((long)GParse & AND_EXP) {
  2735.             success = 0;
  2736.             for (ii=0; ii<num_terminals; ii++) {
  2737.                 if (!matched_terminals[ii]) break;
  2738.             }
  2739.             if (ii >= num_terminals) success = 1;
  2740.         }
  2741.         else {
  2742.             success = 0;
  2743.             /* cannot come to filter_output in this case! */
  2744.         }
  2745.     }
  2746.  
  2747.     /* Print the temporary output onto stdout if search was successful; unlink the temprorary file */
  2748.     if (success) {
  2749.         if (GFILENAMEONLY) {    /* all other output options are useless since they all deal with the MATCHED line */
  2750.             fprintf(stdout, "%s\n", infile);
  2751.             if (storefp != NULL) fclose(storefp); /* don't bother to flush! */
  2752.             storefp = NULL;
  2753.         }
  2754.         else if (storefp != NULL) {
  2755.             fflush(storefp);
  2756.             fclose(storefp);
  2757. #if    DEBUG
  2758.             printf("STOREOUTPUT\n");
  2759.             sprintf(s, "cat %s/.glimpse_storeoutput.%d\n", TEMP_DIR, getpid());
  2760.             system(s);
  2761. #endif    /*DEBUG*/
  2762.             sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  2763.             if ((storefp = fopen(s, "r")) != NULL) {
  2764.                 while (fgets(s, MAX_LINE_LEN, storefp) != NULL) fputs(s, stdout);
  2765.                 fclose(storefp);
  2766.             }
  2767.             storefp = NULL;
  2768.         }
  2769.     }
  2770.     else {
  2771.         if (storefp != NULL) fclose(storefp); /* else don't bother to flush */
  2772.     }
  2773.  
  2774. unlink_and_quit:
  2775.     sprintf(s, "%s/.glimpse_storeoutput.%d", TEMP_DIR, getpid());
  2776.     unlink(s);
  2777.  
  2778.     if (StructuredIndex) region_destroy();
  2779.     fclose(outfp);
  2780.  
  2781.     if (GFILENAMEONLY) {
  2782.         if (numprinted > 0) return 1;
  2783.         else return 0;
  2784.     }
  2785.     else return numprinted;
  2786. }
  2787.  
  2788. usage()
  2789. {
  2790.     fprintf(stderr, "\nThis is glimpse version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  2791.     fprintf(stderr, "usage:  %s [-#abcdehiklnprstwxyBCDGIMSVW] [-F pat] [-H dir] [-J host] [-K port] [-L num] [-R lim] [-T dir] pattern [files]", GProgname);
  2792.     fprintf(stderr, "\n");
  2793.     fprintf(stderr, "summary of frequently used options:\n");
  2794.     fprintf(stderr, "(For a more detailed listing see 'man glimpse'.)\n");
  2795.     fprintf(stderr, "-#: find matches with at most # errors\n");
  2796.     fprintf(stderr, "-c: output the number of matched records\n");
  2797.     fprintf(stderr, "-d: define record delimiter\n");
  2798.     fprintf(stderr, "-h: do not output file names\n");
  2799.     fprintf(stderr, "-i: case-insensitive search, e.g., 'a' = 'A'\n");
  2800.     fprintf(stderr, "-l: output the names of files that contain a match\n");
  2801.     fprintf(stderr, "-n: output record prefixed by record number\n");
  2802.     /* fprintf(stderr, "-v: output those records that have no matches\n"); */
  2803.     fprintf(stderr, "-w: pattern has to match as a word, e.g., 'win' will not match 'wind'\n");
  2804.     fprintf(stderr, "-B: best match mode. find the closest matches to the pattern\n");
  2805.     fprintf(stderr, "-F 'pat': 'pat' is used to match against file names\n");
  2806.     fprintf(stderr, "-G: output the (whole) files that contain a match\n");
  2807.     fprintf(stderr, "-H 'dir': the glimpse index is located in directory 'dir'\n");
  2808.     fprintf(stderr, "-L 'num': limit the output to 'num' records only\n");
  2809.     fprintf(stderr, "\n");
  2810.     fprintf(stderr, "For questions about glimpse, please contact `%s'\n", GLIMPSE_EMAIL);
  2811.  
  2812.     return -1;    /* useful if we make glimpse into a library */
  2813. }
  2814.  
  2815. usageS()
  2816. {
  2817.     fprintf(stderr, "\nThis is glimpse server version %s, %s.\n\n", GLIMPSE_VERSION, GLIMPSE_DATE);
  2818.     fprintf(stderr, "usage:  %s [-H dir] [-J host] [-K port]", GProgname);
  2819.     fprintf(stderr, "\n");
  2820.     fprintf(stderr, "-H 'dir': the glimpse index is located in directory 'dir'\n");
  2821.     fprintf(stderr, "-J 'host': the host name (string) clients must use / server runs on \n");
  2822.     fprintf(stderr, "-K 'port': the port (short integer) clients must use / server runs on \n");
  2823.     fprintf(stderr, "\n");
  2824.     fprintf(stderr, "For questions about glimpse, please contact `%s'\n", GLIMPSE_EMAIL);
  2825.  
  2826.     return -1;    /* useful if we make glimpse into a library */
  2827. }
  2828.  
  2829. #if    CLIENTSERVER
  2830. /*
  2831.  *  do_select() - based on select_loop() from the Harvest Broker.
  2832.  *  -- Courtesy: Darren Hardy, hardy@cs.colorado.edu
  2833.  */
  2834. int do_select(sock, sec)
  2835. int sock;        /* the socket to wait for */
  2836. int sec;        /* the number of seconds to wait */
  2837. {
  2838.     struct timeval to;
  2839.     fd_set qready;
  2840.     int err;
  2841.  
  2842.     if (sock < 0 || sec < 0)
  2843.         return 0;
  2844.  
  2845.     FD_ZERO(&qready);
  2846.     FD_SET(sock, &qready);
  2847.     to.tv_sec = sec;
  2848.     to.tv_usec = 0;
  2849.     if ((err = select(sock + 1, &qready, NULL, NULL, &to)) < 0) {
  2850.         if (errno == EINTR)
  2851.             return 0;
  2852.         perror("select");
  2853.         return -1;
  2854.     }
  2855.     if (err == 0)
  2856.         return 0;
  2857.  
  2858.     /* If there's someone waiting to get it, let them through */
  2859.     return (FD_ISSET(sock, &qready) ? 1 : 0);
  2860. }
  2861. #endif    /* CLIENTSERVER */
  2862.